@bastani/atomic 0.5.11 → 0.5.12-1
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/.agents/skills/adapt/SKILL.md +199 -0
- package/.agents/skills/advanced-evaluation/SKILL.md +402 -0
- package/.agents/skills/advanced-evaluation/references/bias-mitigation.md +288 -0
- package/.agents/skills/advanced-evaluation/references/evaluation-pipeline.md +43 -0
- package/.agents/skills/advanced-evaluation/references/implementation-patterns.md +315 -0
- package/.agents/skills/advanced-evaluation/references/metrics-guide.md +331 -0
- package/.agents/skills/advanced-evaluation/scripts/evaluation_example.py +392 -0
- package/.agents/skills/animate/SKILL.md +175 -0
- package/.agents/skills/arrange/SKILL.md +124 -0
- package/.agents/skills/audit/SKILL.md +148 -0
- package/.agents/skills/bdi-mental-states/SKILL.md +311 -0
- package/.agents/skills/bdi-mental-states/references/bdi-ontology-core.md +207 -0
- package/.agents/skills/bdi-mental-states/references/framework-integration.md +582 -0
- package/.agents/skills/bdi-mental-states/references/rdf-examples.md +315 -0
- package/.agents/skills/bdi-mental-states/references/sparql-competency.md +420 -0
- package/.agents/skills/bolder/SKILL.md +117 -0
- package/.agents/skills/bun/SKILL.md +199 -0
- package/.agents/skills/clarify/SKILL.md +183 -0
- package/.agents/skills/colorize/SKILL.md +143 -0
- package/.agents/skills/context-compression/SKILL.md +272 -0
- package/.agents/skills/context-compression/references/evaluation-framework.md +213 -0
- package/.agents/skills/context-compression/scripts/compression_evaluator.py +862 -0
- package/.agents/skills/context-compression/tests/test_compression_evaluator.py +56 -0
- package/.agents/skills/context-degradation/SKILL.md +206 -0
- package/.agents/skills/context-degradation/references/patterns.md +314 -0
- package/.agents/skills/context-degradation/scripts/degradation_detector.py +614 -0
- package/.agents/skills/context-fundamentals/SKILL.md +201 -0
- package/.agents/skills/context-fundamentals/references/context-components.md +283 -0
- package/.agents/skills/context-fundamentals/scripts/context_manager.py +533 -0
- package/.agents/skills/context-optimization/SKILL.md +195 -0
- package/.agents/skills/context-optimization/references/optimization_techniques.md +272 -0
- package/.agents/skills/context-optimization/scripts/compaction.py +562 -0
- package/.agents/skills/create-spec/SKILL.md +244 -0
- package/.agents/skills/critique/SKILL.md +225 -0
- package/.agents/skills/critique/reference/cognitive-load.md +106 -0
- package/.agents/skills/critique/reference/heuristics-scoring.md +234 -0
- package/.agents/skills/critique/reference/personas.md +178 -0
- package/.agents/skills/delight/SKILL.md +304 -0
- package/.agents/skills/distill/SKILL.md +122 -0
- package/.agents/skills/docx/LICENSE.txt +30 -0
- package/.agents/skills/docx/SKILL.md +590 -0
- package/.agents/skills/docx/scripts/__init__.py +1 -0
- package/.agents/skills/docx/scripts/accept_changes.py +135 -0
- package/.agents/skills/docx/scripts/comment.py +318 -0
- package/.agents/skills/docx/scripts/office/helpers/__init__.py +0 -0
- package/.agents/skills/docx/scripts/office/helpers/merge_runs.py +199 -0
- package/.agents/skills/docx/scripts/office/helpers/simplify_redlines.py +197 -0
- package/.agents/skills/docx/scripts/office/pack.py +159 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/.agents/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/.agents/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/.agents/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/.agents/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/.agents/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/.agents/skills/docx/scripts/office/schemas/mce/mc.xsd +75 -0
- package/.agents/skills/docx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- package/.agents/skills/docx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- package/.agents/skills/docx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- package/.agents/skills/docx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/.agents/skills/docx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/.agents/skills/docx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/.agents/skills/docx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/.agents/skills/docx/scripts/office/soffice.py +183 -0
- package/.agents/skills/docx/scripts/office/unpack.py +132 -0
- package/.agents/skills/docx/scripts/office/validate.py +111 -0
- package/.agents/skills/docx/scripts/office/validators/__init__.py +15 -0
- package/.agents/skills/docx/scripts/office/validators/base.py +847 -0
- package/.agents/skills/docx/scripts/office/validators/docx.py +446 -0
- package/.agents/skills/docx/scripts/office/validators/pptx.py +275 -0
- package/.agents/skills/docx/scripts/office/validators/redlining.py +247 -0
- package/.agents/skills/docx/scripts/templates/comments.xml +3 -0
- package/.agents/skills/docx/scripts/templates/commentsExtended.xml +3 -0
- package/.agents/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/.agents/skills/docx/scripts/templates/commentsIds.xml +3 -0
- package/.agents/skills/docx/scripts/templates/people.xml +3 -0
- package/.agents/skills/evaluation/SKILL.md +251 -0
- package/.agents/skills/evaluation/references/metrics.md +339 -0
- package/.agents/skills/evaluation/scripts/evaluator.py +627 -0
- package/.agents/skills/explain-code/SKILL.md +230 -0
- package/.agents/skills/extract/SKILL.md +91 -0
- package/.agents/skills/filesystem-context/SKILL.md +287 -0
- package/.agents/skills/filesystem-context/references/implementation-patterns.md +549 -0
- package/.agents/skills/filesystem-context/scripts/filesystem_context.py +425 -0
- package/.agents/skills/find-skills/SKILL.md +142 -0
- package/.agents/skills/frontend-design/SKILL.md +147 -0
- package/.agents/skills/frontend-design/reference/color-and-contrast.md +132 -0
- package/.agents/skills/frontend-design/reference/interaction-design.md +195 -0
- package/.agents/skills/frontend-design/reference/motion-design.md +99 -0
- package/.agents/skills/frontend-design/reference/responsive-design.md +114 -0
- package/.agents/skills/frontend-design/reference/spatial-design.md +100 -0
- package/.agents/skills/frontend-design/reference/typography.md +133 -0
- package/.agents/skills/frontend-design/reference/ux-writing.md +107 -0
- package/.agents/skills/gh-commit/SKILL.md +243 -0
- package/.agents/skills/gh-create-pr/SKILL.md +93 -0
- package/.agents/skills/harden/SKILL.md +354 -0
- package/.agents/skills/hosted-agents/SKILL.md +260 -0
- package/.agents/skills/hosted-agents/references/infrastructure-patterns.md +700 -0
- package/.agents/skills/hosted-agents/scripts/sandbox_manager.py +590 -0
- package/.agents/skills/impeccable/SKILL.md +365 -0
- package/.agents/skills/impeccable/reference/color-and-contrast.md +105 -0
- package/.agents/skills/impeccable/reference/craft.md +70 -0
- package/.agents/skills/impeccable/reference/extract.md +70 -0
- package/.agents/skills/impeccable/reference/interaction-design.md +195 -0
- package/.agents/skills/impeccable/reference/motion-design.md +99 -0
- package/.agents/skills/impeccable/reference/responsive-design.md +114 -0
- package/.agents/skills/impeccable/reference/spatial-design.md +100 -0
- package/.agents/skills/impeccable/reference/typography.md +142 -0
- package/.agents/skills/impeccable/reference/ux-writing.md +107 -0
- package/.agents/skills/impeccable/scripts/cleanup-deprecated.mjs +214 -0
- package/.agents/skills/init/SKILL.md +138 -0
- package/.agents/skills/layout/SKILL.md +125 -0
- package/.agents/skills/liteparse/SKILL.md +222 -0
- package/.agents/skills/memory-systems/SKILL.md +219 -0
- package/.agents/skills/memory-systems/references/implementation.md +551 -0
- package/.agents/skills/memory-systems/scripts/memory_store.py +616 -0
- package/.agents/skills/multi-agent-patterns/SKILL.md +257 -0
- package/.agents/skills/multi-agent-patterns/references/frameworks.md +433 -0
- package/.agents/skills/multi-agent-patterns/scripts/coordination.py +613 -0
- package/.agents/skills/normalize/SKILL.md +70 -0
- package/.agents/skills/onboard/SKILL.md +245 -0
- package/.agents/skills/opentui/SKILL.md +201 -0
- package/.agents/skills/opentui/references/animation/REFERENCE.md +431 -0
- package/.agents/skills/opentui/references/components/REFERENCE.md +144 -0
- package/.agents/skills/opentui/references/components/code-diff.md +672 -0
- package/.agents/skills/opentui/references/components/containers.md +417 -0
- package/.agents/skills/opentui/references/components/inputs.md +531 -0
- package/.agents/skills/opentui/references/components/text-display.md +386 -0
- package/.agents/skills/opentui/references/core/REFERENCE.md +145 -0
- package/.agents/skills/opentui/references/core/api.md +543 -0
- package/.agents/skills/opentui/references/core/configuration.md +168 -0
- package/.agents/skills/opentui/references/core/gotchas.md +393 -0
- package/.agents/skills/opentui/references/core/patterns.md +449 -0
- package/.agents/skills/opentui/references/keyboard/REFERENCE.md +617 -0
- package/.agents/skills/opentui/references/layout/REFERENCE.md +337 -0
- package/.agents/skills/opentui/references/layout/patterns.md +444 -0
- package/.agents/skills/opentui/references/react/REFERENCE.md +174 -0
- package/.agents/skills/opentui/references/react/api.md +436 -0
- package/.agents/skills/opentui/references/react/configuration.md +302 -0
- package/.agents/skills/opentui/references/react/gotchas.md +443 -0
- package/.agents/skills/opentui/references/react/patterns.md +501 -0
- package/.agents/skills/opentui/references/solid/REFERENCE.md +201 -0
- package/.agents/skills/opentui/references/solid/api.md +564 -0
- package/.agents/skills/opentui/references/solid/configuration.md +316 -0
- package/.agents/skills/opentui/references/solid/gotchas.md +427 -0
- package/.agents/skills/opentui/references/solid/patterns.md +560 -0
- package/.agents/skills/opentui/references/testing/REFERENCE.md +614 -0
- package/.agents/skills/optimize/SKILL.md +266 -0
- package/.agents/skills/overdrive/SKILL.md +142 -0
- package/.agents/skills/pdf/LICENSE.txt +30 -0
- package/.agents/skills/pdf/SKILL.md +314 -0
- package/.agents/skills/pdf/forms.md +294 -0
- package/.agents/skills/pdf/reference.md +612 -0
- package/.agents/skills/pdf/scripts/check_bounding_boxes.py +65 -0
- package/.agents/skills/pdf/scripts/check_fillable_fields.py +11 -0
- package/.agents/skills/pdf/scripts/convert_pdf_to_images.py +33 -0
- package/.agents/skills/pdf/scripts/create_validation_image.py +37 -0
- package/.agents/skills/pdf/scripts/extract_form_field_info.py +122 -0
- package/.agents/skills/pdf/scripts/extract_form_structure.py +115 -0
- package/.agents/skills/pdf/scripts/fill_fillable_fields.py +98 -0
- package/.agents/skills/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
- package/.agents/skills/playwright-cli/SKILL.md +344 -0
- package/.agents/skills/playwright-cli/references/element-attributes.md +23 -0
- package/.agents/skills/playwright-cli/references/playwright-tests.md +39 -0
- package/.agents/skills/playwright-cli/references/request-mocking.md +87 -0
- package/.agents/skills/playwright-cli/references/running-code.md +231 -0
- package/.agents/skills/playwright-cli/references/session-management.md +169 -0
- package/.agents/skills/playwright-cli/references/storage-state.md +275 -0
- package/.agents/skills/playwright-cli/references/test-generation.md +88 -0
- package/.agents/skills/playwright-cli/references/tracing.md +139 -0
- package/.agents/skills/playwright-cli/references/video-recording.md +143 -0
- package/.agents/skills/polish/SKILL.md +224 -0
- package/.agents/skills/pptx/LICENSE.txt +30 -0
- package/.agents/skills/pptx/SKILL.md +232 -0
- package/.agents/skills/pptx/editing.md +205 -0
- package/.agents/skills/pptx/pptxgenjs.md +420 -0
- package/.agents/skills/pptx/scripts/__init__.py +0 -0
- package/.agents/skills/pptx/scripts/add_slide.py +195 -0
- package/.agents/skills/pptx/scripts/clean.py +286 -0
- package/.agents/skills/pptx/scripts/office/helpers/__init__.py +0 -0
- package/.agents/skills/pptx/scripts/office/helpers/merge_runs.py +199 -0
- package/.agents/skills/pptx/scripts/office/helpers/simplify_redlines.py +197 -0
- package/.agents/skills/pptx/scripts/office/pack.py +159 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/.agents/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/.agents/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/.agents/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/.agents/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/.agents/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/.agents/skills/pptx/scripts/office/schemas/mce/mc.xsd +75 -0
- package/.agents/skills/pptx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- package/.agents/skills/pptx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- package/.agents/skills/pptx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- package/.agents/skills/pptx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/.agents/skills/pptx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/.agents/skills/pptx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/.agents/skills/pptx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/.agents/skills/pptx/scripts/office/soffice.py +183 -0
- package/.agents/skills/pptx/scripts/office/unpack.py +132 -0
- package/.agents/skills/pptx/scripts/office/validate.py +111 -0
- package/.agents/skills/pptx/scripts/office/validators/__init__.py +15 -0
- package/.agents/skills/pptx/scripts/office/validators/base.py +847 -0
- package/.agents/skills/pptx/scripts/office/validators/docx.py +446 -0
- package/.agents/skills/pptx/scripts/office/validators/pptx.py +275 -0
- package/.agents/skills/pptx/scripts/office/validators/redlining.py +247 -0
- package/.agents/skills/pptx/scripts/thumbnail.py +289 -0
- package/.agents/skills/project-development/SKILL.md +291 -0
- package/.agents/skills/project-development/references/case-studies.md +388 -0
- package/.agents/skills/project-development/references/pipeline-patterns.md +610 -0
- package/.agents/skills/project-development/scripts/pipeline_template.py +796 -0
- package/.agents/skills/prompt-engineer/SKILL.md +263 -0
- package/.agents/skills/prompt-engineer/references/advanced_patterns.md +271 -0
- package/.agents/skills/prompt-engineer/references/core_prompting.md +137 -0
- package/.agents/skills/prompt-engineer/references/quality_improvement.md +193 -0
- package/.agents/skills/quieter/SKILL.md +103 -0
- package/.agents/skills/research-codebase/SKILL.md +227 -0
- package/.agents/skills/shape/SKILL.md +96 -0
- package/.agents/skills/skill-creator/LICENSE.txt +202 -0
- package/.agents/skills/skill-creator/SKILL.md +485 -0
- package/.agents/skills/skill-creator/agents/analyzer.md +274 -0
- package/.agents/skills/skill-creator/agents/comparator.md +202 -0
- package/.agents/skills/skill-creator/agents/grader.md +223 -0
- package/.agents/skills/skill-creator/assets/eval_review.html +146 -0
- package/.agents/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/.agents/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/.agents/skills/skill-creator/references/schemas.md +430 -0
- package/.agents/skills/skill-creator/scripts/__init__.py +0 -0
- package/.agents/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/.agents/skills/skill-creator/scripts/generate_report.py +326 -0
- package/.agents/skills/skill-creator/scripts/improve_description.py +247 -0
- package/.agents/skills/skill-creator/scripts/package_skill.py +136 -0
- package/.agents/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/.agents/skills/skill-creator/scripts/run_eval.py +310 -0
- package/.agents/skills/skill-creator/scripts/run_loop.py +328 -0
- package/.agents/skills/skill-creator/scripts/utils.py +47 -0
- package/.agents/skills/sl-commit/SKILL.md +51 -0
- package/.agents/skills/sl-submit-diff/SKILL.md +55 -0
- package/.agents/skills/teach-impeccable/SKILL.md +71 -0
- package/.agents/skills/test-driven-development/SKILL.md +371 -0
- package/.agents/skills/test-driven-development/testing-anti-patterns.md +299 -0
- package/.agents/skills/tool-design/SKILL.md +271 -0
- package/.agents/skills/tool-design/references/architectural_reduction.md +210 -0
- package/.agents/skills/tool-design/references/best_practices.md +176 -0
- package/.agents/skills/tool-design/scripts/description_generator.py +528 -0
- package/.agents/skills/typescript-advanced-types/SKILL.md +719 -0
- package/.agents/skills/typescript-expert/SKILL.md +428 -0
- package/.agents/skills/typescript-expert/references/tsconfig-strict.json +92 -0
- package/.agents/skills/typescript-expert/references/typescript-cheatsheet.md +383 -0
- package/.agents/skills/typescript-expert/references/utility-types.ts +335 -0
- package/.agents/skills/typescript-expert/scripts/ts_diagnostic.py +203 -0
- package/.agents/skills/typescript-react-reviewer/SKILL.md +200 -0
- package/.agents/skills/typescript-react-reviewer/references/antipatterns.md +510 -0
- package/.agents/skills/typescript-react-reviewer/references/checklist.md +267 -0
- package/.agents/skills/typescript-react-reviewer/references/react19-patterns.md +305 -0
- package/.agents/skills/typeset/SKILL.md +116 -0
- package/.agents/skills/workflow-creator/SKILL.md +337 -0
- package/.agents/skills/workflow-creator/references/agent-sessions.md +789 -0
- package/.agents/skills/workflow-creator/references/computation-and-validation.md +224 -0
- package/.agents/skills/workflow-creator/references/control-flow.md +450 -0
- package/.agents/skills/workflow-creator/references/discovery-and-verification.md +156 -0
- package/.agents/skills/workflow-creator/references/failure-modes.md +732 -0
- package/.agents/skills/workflow-creator/references/getting-started.md +289 -0
- package/.agents/skills/workflow-creator/references/session-config.md +355 -0
- package/.agents/skills/workflow-creator/references/state-and-data-flow.md +374 -0
- package/.agents/skills/workflow-creator/references/user-input.md +206 -0
- package/.agents/skills/workflow-creator/references/workflow-inputs.md +274 -0
- package/.agents/skills/xlsx/LICENSE.txt +30 -0
- package/.agents/skills/xlsx/SKILL.md +292 -0
- package/.agents/skills/xlsx/scripts/office/helpers/__init__.py +0 -0
- package/.agents/skills/xlsx/scripts/office/helpers/merge_runs.py +199 -0
- package/.agents/skills/xlsx/scripts/office/helpers/simplify_redlines.py +197 -0
- package/.agents/skills/xlsx/scripts/office/pack.py +159 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/.agents/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/.agents/skills/xlsx/scripts/office/schemas/mce/mc.xsd +75 -0
- package/.agents/skills/xlsx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- package/.agents/skills/xlsx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- package/.agents/skills/xlsx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- package/.agents/skills/xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/.agents/skills/xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/.agents/skills/xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/.agents/skills/xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/.agents/skills/xlsx/scripts/office/soffice.py +183 -0
- package/.agents/skills/xlsx/scripts/office/unpack.py +132 -0
- package/.agents/skills/xlsx/scripts/office/validate.py +111 -0
- package/.agents/skills/xlsx/scripts/office/validators/__init__.py +15 -0
- package/.agents/skills/xlsx/scripts/office/validators/base.py +847 -0
- package/.agents/skills/xlsx/scripts/office/validators/docx.py +446 -0
- package/.agents/skills/xlsx/scripts/office/validators/pptx.py +275 -0
- package/.agents/skills/xlsx/scripts/office/validators/redlining.py +247 -0
- package/.agents/skills/xlsx/scripts/recalc.py +184 -0
- package/.claude/agents/reviewer.md +1 -0
- package/.github/agents/reviewer.md +1 -0
- package/.opencode/agents/reviewer.md +1 -0
- package/README.md +274 -169
- package/package.json +6 -7
- package/src/commands/cli/init/index.ts +2 -2
- package/src/commands/cli/init/scm.ts +7 -8
- package/src/commands/cli/workflow-command.test.ts +74 -0
- package/src/commands/cli/workflow.ts +7 -2
- package/src/scripts/bundle-configs.ts +128 -0
- package/src/sdk/components/compact-switcher.tsx +1 -1
- package/src/sdk/components/orchestrator-panel-store.ts +13 -0
- package/src/sdk/components/orchestrator-panel.tsx +10 -0
- package/src/sdk/components/statusline.tsx +13 -1
- package/src/sdk/components/workflow-picker-panel.tsx +407 -296
- package/src/sdk/providers/claude.ts +50 -0
- package/src/sdk/runtime/executor.ts +111 -32
- package/src/sdk/types.ts +7 -0
- package/src/sdk/workflows/builtin/ralph/claude/index.ts +132 -76
- package/src/sdk/workflows/builtin/ralph/copilot/index.ts +129 -71
- package/src/sdk/workflows/builtin/ralph/helpers/git.ts +184 -17
- package/src/sdk/workflows/builtin/ralph/helpers/prompts.ts +463 -79
- package/src/sdk/workflows/builtin/ralph/opencode/index.ts +124 -80
- package/src/services/system/auto-sync.ts +31 -51
- package/src/services/system/skills.ts +56 -60
- package/dist/lib/path-root-guard.d.ts +0 -4
- package/dist/lib/path-root-guard.d.ts.map +0 -1
- package/dist/sdk/components/color-utils.d.ts +0 -4
- package/dist/sdk/components/color-utils.d.ts.map +0 -1
- package/dist/sdk/components/compact-switcher.d.ts +0 -10
- package/dist/sdk/components/compact-switcher.d.ts.map +0 -1
- package/dist/sdk/components/connectors.d.ts +0 -15
- package/dist/sdk/components/connectors.d.ts.map +0 -1
- package/dist/sdk/components/connectors.test.d.ts +0 -2
- package/dist/sdk/components/connectors.test.d.ts.map +0 -1
- package/dist/sdk/components/edge.d.ts +0 -4
- package/dist/sdk/components/edge.d.ts.map +0 -1
- package/dist/sdk/components/error-boundary.d.ts +0 -23
- package/dist/sdk/components/error-boundary.d.ts.map +0 -1
- package/dist/sdk/components/graph-theme.d.ts +0 -17
- package/dist/sdk/components/graph-theme.d.ts.map +0 -1
- package/dist/sdk/components/header.d.ts +0 -3
- package/dist/sdk/components/header.d.ts.map +0 -1
- package/dist/sdk/components/hooks.d.ts +0 -15
- package/dist/sdk/components/hooks.d.ts.map +0 -1
- package/dist/sdk/components/layout.d.ts +0 -27
- package/dist/sdk/components/layout.d.ts.map +0 -1
- package/dist/sdk/components/layout.test.d.ts +0 -2
- package/dist/sdk/components/layout.test.d.ts.map +0 -1
- package/dist/sdk/components/node-card.d.ts +0 -10
- package/dist/sdk/components/node-card.d.ts.map +0 -1
- package/dist/sdk/components/orchestrator-panel-contexts.d.ts +0 -16
- package/dist/sdk/components/orchestrator-panel-contexts.d.ts.map +0 -1
- package/dist/sdk/components/orchestrator-panel-store.d.ts +0 -46
- package/dist/sdk/components/orchestrator-panel-store.d.ts.map +0 -1
- package/dist/sdk/components/orchestrator-panel-store.test.d.ts +0 -2
- package/dist/sdk/components/orchestrator-panel-store.test.d.ts.map +0 -1
- package/dist/sdk/components/orchestrator-panel-types.d.ts +0 -18
- package/dist/sdk/components/orchestrator-panel-types.d.ts.map +0 -1
- package/dist/sdk/components/orchestrator-panel.d.ts +0 -52
- package/dist/sdk/components/orchestrator-panel.d.ts.map +0 -1
- package/dist/sdk/components/session-graph-panel.d.ts +0 -7
- package/dist/sdk/components/session-graph-panel.d.ts.map +0 -1
- package/dist/sdk/components/status-helpers.d.ts +0 -6
- package/dist/sdk/components/status-helpers.d.ts.map +0 -1
- package/dist/sdk/components/statusline.d.ts +0 -7
- package/dist/sdk/components/statusline.d.ts.map +0 -1
- package/dist/sdk/components/workflow-picker-panel.d.ts +0 -123
- package/dist/sdk/components/workflow-picker-panel.d.ts.map +0 -1
- package/dist/sdk/define-workflow.d.ts +0 -78
- package/dist/sdk/define-workflow.d.ts.map +0 -1
- package/dist/sdk/define-workflow.test.d.ts +0 -2
- package/dist/sdk/define-workflow.test.d.ts.map +0 -1
- package/dist/sdk/errors.d.ts +0 -24
- package/dist/sdk/errors.d.ts.map +0 -1
- package/dist/sdk/errors.test.d.ts +0 -2
- package/dist/sdk/errors.test.d.ts.map +0 -1
- package/dist/sdk/index.d.ts +0 -13
- package/dist/sdk/index.d.ts.map +0 -1
- package/dist/sdk/providers/claude.d.ts +0 -170
- package/dist/sdk/providers/claude.d.ts.map +0 -1
- package/dist/sdk/providers/copilot.d.ts +0 -11
- package/dist/sdk/providers/copilot.d.ts.map +0 -1
- package/dist/sdk/providers/opencode.d.ts +0 -11
- package/dist/sdk/providers/opencode.d.ts.map +0 -1
- package/dist/sdk/runtime/discovery.d.ts +0 -86
- package/dist/sdk/runtime/discovery.d.ts.map +0 -1
- package/dist/sdk/runtime/executor-entry.d.ts +0 -11
- package/dist/sdk/runtime/executor-entry.d.ts.map +0 -1
- package/dist/sdk/runtime/executor.d.ts +0 -72
- package/dist/sdk/runtime/executor.d.ts.map +0 -1
- package/dist/sdk/runtime/executor.test.d.ts +0 -2
- package/dist/sdk/runtime/executor.test.d.ts.map +0 -1
- package/dist/sdk/runtime/graph-inference.d.ts +0 -35
- package/dist/sdk/runtime/graph-inference.d.ts.map +0 -1
- package/dist/sdk/runtime/loader.d.ts +0 -70
- package/dist/sdk/runtime/loader.d.ts.map +0 -1
- package/dist/sdk/runtime/panel.d.ts +0 -9
- package/dist/sdk/runtime/panel.d.ts.map +0 -1
- package/dist/sdk/runtime/theme.d.ts +0 -28
- package/dist/sdk/runtime/theme.d.ts.map +0 -1
- package/dist/sdk/runtime/tmux.d.ts +0 -297
- package/dist/sdk/runtime/tmux.d.ts.map +0 -1
- package/dist/sdk/types.d.ts +0 -295
- package/dist/sdk/types.d.ts.map +0 -1
- package/dist/sdk/workflows/builtin/deep-research-codebase/claude/index.d.ts +0 -62
- package/dist/sdk/workflows/builtin/deep-research-codebase/claude/index.d.ts.map +0 -1
- package/dist/sdk/workflows/builtin/deep-research-codebase/copilot/index.d.ts +0 -46
- package/dist/sdk/workflows/builtin/deep-research-codebase/copilot/index.d.ts.map +0 -1
- package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/heuristic.d.ts +0 -26
- package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/heuristic.d.ts.map +0 -1
- package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/prompts.d.ts +0 -92
- package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/prompts.d.ts.map +0 -1
- package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/scout.d.ts +0 -57
- package/dist/sdk/workflows/builtin/deep-research-codebase/helpers/scout.d.ts.map +0 -1
- package/dist/sdk/workflows/builtin/deep-research-codebase/opencode/index.d.ts +0 -49
- package/dist/sdk/workflows/builtin/deep-research-codebase/opencode/index.d.ts.map +0 -1
- package/dist/sdk/workflows/builtin/ralph/claude/index.d.ts +0 -14
- package/dist/sdk/workflows/builtin/ralph/claude/index.d.ts.map +0 -1
- package/dist/sdk/workflows/builtin/ralph/copilot/index.d.ts +0 -14
- package/dist/sdk/workflows/builtin/ralph/copilot/index.d.ts.map +0 -1
- package/dist/sdk/workflows/builtin/ralph/helpers/git.d.ts +0 -17
- package/dist/sdk/workflows/builtin/ralph/helpers/git.d.ts.map +0 -1
- package/dist/sdk/workflows/builtin/ralph/helpers/prompts.d.ts +0 -119
- package/dist/sdk/workflows/builtin/ralph/helpers/prompts.d.ts.map +0 -1
- package/dist/sdk/workflows/builtin/ralph/helpers/review.d.ts +0 -20
- package/dist/sdk/workflows/builtin/ralph/helpers/review.d.ts.map +0 -1
- package/dist/sdk/workflows/builtin/ralph/opencode/index.d.ts +0 -14
- package/dist/sdk/workflows/builtin/ralph/opencode/index.d.ts.map +0 -1
- package/dist/sdk/workflows/index.d.ts +0 -24
- package/dist/sdk/workflows/index.d.ts.map +0 -1
- package/dist/services/config/definitions.d.ts +0 -85
- package/dist/services/config/definitions.d.ts.map +0 -1
- package/dist/services/system/copy.d.ts +0 -77
- package/dist/services/system/copy.d.ts.map +0 -1
- package/dist/services/system/detect.d.ts +0 -75
- package/dist/services/system/detect.d.ts.map +0 -1
- package/tsconfig.json +0 -33
|
@@ -0,0 +1,796 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LLM Batch Processing Pipeline Template.
|
|
3
|
+
|
|
4
|
+
A composable, staged pipeline architecture for LLM batch processing.
|
|
5
|
+
Each stage is discrete, idempotent, and cacheable. Customize the acquire,
|
|
6
|
+
prepare, process, parse, and render functions for your use case.
|
|
7
|
+
|
|
8
|
+
Use when:
|
|
9
|
+
- Building a new batch processing pipeline with structured LLM outputs
|
|
10
|
+
- Prototyping an acquire -> prepare -> process -> parse -> render workflow
|
|
11
|
+
- Need a file-system-based state machine for pipeline stage tracking
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
python pipeline_template.py acquire --batch-id 2025-01-15
|
|
15
|
+
python pipeline_template.py prepare --batch-id 2025-01-15
|
|
16
|
+
python pipeline_template.py process --batch-id 2025-01-15 --workers 10
|
|
17
|
+
python pipeline_template.py parse --batch-id 2025-01-15
|
|
18
|
+
python pipeline_template.py render --batch-id 2025-01-15
|
|
19
|
+
python pipeline_template.py all --batch-id 2025-01-15
|
|
20
|
+
python pipeline_template.py clean --batch-id 2025-01-15 --clean-stage process
|
|
21
|
+
python pipeline_template.py estimate --batch-id 2025-01-15
|
|
22
|
+
|
|
23
|
+
Programmatic usage:
|
|
24
|
+
from pipeline_template import stage_acquire, stage_prepare, stage_process
|
|
25
|
+
stage_acquire("2025-01-15", limit=5)
|
|
26
|
+
stage_prepare("2025-01-15")
|
|
27
|
+
stage_process("2025-01-15", model="claude-sonnet-4-20250514", max_workers=3)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
import argparse
|
|
31
|
+
import json
|
|
32
|
+
import re
|
|
33
|
+
import time
|
|
34
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
35
|
+
from dataclasses import dataclass, field, asdict
|
|
36
|
+
from datetime import date
|
|
37
|
+
from pathlib import Path
|
|
38
|
+
from typing import Any
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"Item",
|
|
42
|
+
"ParsedResult",
|
|
43
|
+
"stage_acquire",
|
|
44
|
+
"stage_prepare",
|
|
45
|
+
"stage_process",
|
|
46
|
+
"stage_parse",
|
|
47
|
+
"stage_render",
|
|
48
|
+
"stage_clean",
|
|
49
|
+
"stage_estimate",
|
|
50
|
+
"parse_response",
|
|
51
|
+
"get_batch_dir",
|
|
52
|
+
"get_item_dir",
|
|
53
|
+
"get_output_dir",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# -----------------------------------------------------------------------------
|
|
58
|
+
# Configuration - Customize for your use case
|
|
59
|
+
# -----------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
DATA_DIR = Path("data")
|
|
62
|
+
OUTPUT_DIR = Path("output")
|
|
63
|
+
|
|
64
|
+
# Prompt template with structured output requirements
|
|
65
|
+
PROMPT_TEMPLATE = """Analyze the following content and provide your response in exactly this format.
|
|
66
|
+
|
|
67
|
+
## Summary
|
|
68
|
+
[2-3 sentence summary of the content]
|
|
69
|
+
|
|
70
|
+
## Key Points
|
|
71
|
+
- [Point 1]
|
|
72
|
+
- [Point 2]
|
|
73
|
+
- [Point 3]
|
|
74
|
+
|
|
75
|
+
## Score
|
|
76
|
+
Rating: [1-10]
|
|
77
|
+
Confidence: [low/medium/high]
|
|
78
|
+
|
|
79
|
+
## Reasoning
|
|
80
|
+
[Explanation of your analysis]
|
|
81
|
+
|
|
82
|
+
Follow this format exactly because I will be parsing it programmatically.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
# Content to Analyze
|
|
87
|
+
|
|
88
|
+
Title: {title}
|
|
89
|
+
|
|
90
|
+
{content}
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# -----------------------------------------------------------------------------
|
|
95
|
+
# Data Structures
|
|
96
|
+
# -----------------------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
@dataclass
|
|
99
|
+
class Item:
|
|
100
|
+
"""Represents a single item to process through the pipeline.
|
|
101
|
+
|
|
102
|
+
Use when: creating items during the acquire stage or loading raw data
|
|
103
|
+
from any source (API, database, file system).
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
id: str
|
|
107
|
+
title: str
|
|
108
|
+
content: str
|
|
109
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@dataclass
|
|
113
|
+
class ParsedResult:
|
|
114
|
+
"""Structured result from LLM response parsing.
|
|
115
|
+
|
|
116
|
+
Use when: extracting structured data from free-text LLM responses
|
|
117
|
+
during the parse stage.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
summary: str = ""
|
|
121
|
+
key_points: list[str] = field(default_factory=list)
|
|
122
|
+
score: int | None = None
|
|
123
|
+
confidence: str = ""
|
|
124
|
+
reasoning: str = ""
|
|
125
|
+
parse_errors: list[str] = field(default_factory=list)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# -----------------------------------------------------------------------------
|
|
129
|
+
# Path Utilities
|
|
130
|
+
# -----------------------------------------------------------------------------
|
|
131
|
+
|
|
132
|
+
def get_batch_dir(batch_id: str) -> Path:
|
|
133
|
+
"""Get the data directory for a batch.
|
|
134
|
+
|
|
135
|
+
Use when: resolving the root directory for a specific batch run.
|
|
136
|
+
"""
|
|
137
|
+
return DATA_DIR / batch_id
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def get_item_dir(batch_id: str, item_id: str) -> Path:
|
|
141
|
+
"""Get the directory for a specific item.
|
|
142
|
+
|
|
143
|
+
Use when: locating stage output files for a single pipeline item.
|
|
144
|
+
"""
|
|
145
|
+
return get_batch_dir(batch_id) / item_id
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def get_output_dir(batch_id: str) -> Path:
|
|
149
|
+
"""Get the output directory for a batch.
|
|
150
|
+
|
|
151
|
+
Use when: writing final rendered outputs (HTML, reports, etc.).
|
|
152
|
+
"""
|
|
153
|
+
return OUTPUT_DIR / batch_id
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# -----------------------------------------------------------------------------
|
|
157
|
+
# Stage: Acquire
|
|
158
|
+
# -----------------------------------------------------------------------------
|
|
159
|
+
|
|
160
|
+
def stage_acquire(batch_id: str, limit: int | None = None) -> list[Path]:
|
|
161
|
+
"""Stage 1: Acquire raw data from sources.
|
|
162
|
+
|
|
163
|
+
Use when: fetching data from APIs, databases, or file systems
|
|
164
|
+
and persisting it as raw.json per item for downstream stages.
|
|
165
|
+
|
|
166
|
+
Output: {batch_dir}/{item_id}/raw.json
|
|
167
|
+
Returns: List of item directories that were acquired.
|
|
168
|
+
"""
|
|
169
|
+
batch_dir = get_batch_dir(batch_id)
|
|
170
|
+
batch_dir.mkdir(parents=True, exist_ok=True)
|
|
171
|
+
|
|
172
|
+
# CUSTOMIZE: Replace with your data acquisition logic
|
|
173
|
+
items = fetch_items_from_source(limit)
|
|
174
|
+
|
|
175
|
+
acquired_dirs: list[Path] = []
|
|
176
|
+
for item in items:
|
|
177
|
+
item_dir = get_item_dir(batch_id, item.id)
|
|
178
|
+
item_dir.mkdir(exist_ok=True)
|
|
179
|
+
|
|
180
|
+
raw_file = item_dir / "raw.json"
|
|
181
|
+
if not raw_file.exists():
|
|
182
|
+
with open(raw_file, "w") as f:
|
|
183
|
+
json.dump(asdict(item), f, indent=2)
|
|
184
|
+
print(f"Acquired: {item.id}")
|
|
185
|
+
else:
|
|
186
|
+
print(f"Cached: {item.id}")
|
|
187
|
+
|
|
188
|
+
acquired_dirs.append(item_dir)
|
|
189
|
+
|
|
190
|
+
print(f"\nAcquire complete. {len(items)} items in {batch_dir}")
|
|
191
|
+
return acquired_dirs
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def fetch_items_from_source(limit: int | None = None) -> list[Item]:
|
|
195
|
+
"""CUSTOMIZE: Implement your data fetching logic here.
|
|
196
|
+
|
|
197
|
+
Use when: pulling raw items from your specific data source.
|
|
198
|
+
Replace this with actual API calls, database queries, etc.
|
|
199
|
+
"""
|
|
200
|
+
# Example: Generate sample items
|
|
201
|
+
items: list[Item] = []
|
|
202
|
+
for i in range(limit or 10):
|
|
203
|
+
items.append(Item(
|
|
204
|
+
id=f"item-{i:04d}",
|
|
205
|
+
title=f"Sample Item {i}",
|
|
206
|
+
content=f"This is sample content for item {i}. " * 10,
|
|
207
|
+
metadata={"source": "example", "index": i},
|
|
208
|
+
))
|
|
209
|
+
return items
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
# -----------------------------------------------------------------------------
|
|
213
|
+
# Stage: Prepare
|
|
214
|
+
# -----------------------------------------------------------------------------
|
|
215
|
+
|
|
216
|
+
def stage_prepare(batch_id: str) -> int:
|
|
217
|
+
"""Stage 2: Generate prompts from raw data.
|
|
218
|
+
|
|
219
|
+
Use when: transforming raw acquired data into LLM-ready prompts
|
|
220
|
+
using the configured PROMPT_TEMPLATE.
|
|
221
|
+
|
|
222
|
+
Output: {batch_dir}/{item_id}/prompt.md
|
|
223
|
+
Returns: Number of items prepared.
|
|
224
|
+
"""
|
|
225
|
+
batch_dir = get_batch_dir(batch_id)
|
|
226
|
+
prepared_count = 0
|
|
227
|
+
|
|
228
|
+
for item_dir in sorted(batch_dir.iterdir()):
|
|
229
|
+
if not item_dir.is_dir():
|
|
230
|
+
continue
|
|
231
|
+
|
|
232
|
+
raw_file = item_dir / "raw.json"
|
|
233
|
+
prompt_file = item_dir / "prompt.md"
|
|
234
|
+
|
|
235
|
+
if not raw_file.exists():
|
|
236
|
+
continue
|
|
237
|
+
|
|
238
|
+
if prompt_file.exists():
|
|
239
|
+
continue
|
|
240
|
+
|
|
241
|
+
with open(raw_file) as f:
|
|
242
|
+
item_data: dict[str, Any] = json.load(f)
|
|
243
|
+
|
|
244
|
+
prompt = generate_prompt(item_data)
|
|
245
|
+
|
|
246
|
+
with open(prompt_file, "w") as f:
|
|
247
|
+
f.write(prompt)
|
|
248
|
+
|
|
249
|
+
prepared_count += 1
|
|
250
|
+
print(f"Prepared: {item_dir.name}")
|
|
251
|
+
|
|
252
|
+
print(f"\nPrepare complete. {prepared_count} items prepared.")
|
|
253
|
+
return prepared_count
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def generate_prompt(item_data: dict[str, Any]) -> str:
|
|
257
|
+
"""Generate prompt from item data using template.
|
|
258
|
+
|
|
259
|
+
Use when: converting a raw item dict into a formatted prompt string.
|
|
260
|
+
"""
|
|
261
|
+
return PROMPT_TEMPLATE.format(
|
|
262
|
+
title=item_data.get("title", "Untitled"),
|
|
263
|
+
content=item_data.get("content", ""),
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
# -----------------------------------------------------------------------------
|
|
268
|
+
# Stage: Process
|
|
269
|
+
# -----------------------------------------------------------------------------
|
|
270
|
+
|
|
271
|
+
def stage_process(
|
|
272
|
+
batch_id: str,
|
|
273
|
+
model: str = "claude-sonnet-4-20250514",
|
|
274
|
+
max_workers: int = 5,
|
|
275
|
+
) -> list[tuple[str, int, str | None]]:
|
|
276
|
+
"""Stage 3: Execute LLM calls (the expensive, non-deterministic stage).
|
|
277
|
+
|
|
278
|
+
Use when: sending prepared prompts to the LLM API and caching
|
|
279
|
+
responses. This is the only non-deterministic stage.
|
|
280
|
+
|
|
281
|
+
Output: {batch_dir}/{item_id}/response.md
|
|
282
|
+
Returns: List of (item_id, char_count, error_or_none) tuples.
|
|
283
|
+
"""
|
|
284
|
+
batch_dir = get_batch_dir(batch_id)
|
|
285
|
+
|
|
286
|
+
# Collect items needing processing
|
|
287
|
+
to_process: list[tuple[Path, str]] = []
|
|
288
|
+
for item_dir in sorted(batch_dir.iterdir()):
|
|
289
|
+
if not item_dir.is_dir():
|
|
290
|
+
continue
|
|
291
|
+
|
|
292
|
+
prompt_file = item_dir / "prompt.md"
|
|
293
|
+
response_file = item_dir / "response.md"
|
|
294
|
+
|
|
295
|
+
if prompt_file.exists() and not response_file.exists():
|
|
296
|
+
to_process.append((item_dir, prompt_file.read_text()))
|
|
297
|
+
|
|
298
|
+
if not to_process:
|
|
299
|
+
print("No items to process.")
|
|
300
|
+
return []
|
|
301
|
+
|
|
302
|
+
print(f"Processing {len(to_process)} items with {max_workers} workers...")
|
|
303
|
+
|
|
304
|
+
results: list[tuple[str, int, str | None]] = []
|
|
305
|
+
|
|
306
|
+
def process_one(args: tuple[Path, str]) -> tuple[str, int, str | None]:
|
|
307
|
+
item_dir, prompt = args
|
|
308
|
+
response_file = item_dir / "response.md"
|
|
309
|
+
|
|
310
|
+
try:
|
|
311
|
+
# CUSTOMIZE: Replace with your LLM API call
|
|
312
|
+
response = call_llm(prompt, model)
|
|
313
|
+
|
|
314
|
+
with open(response_file, "w") as f:
|
|
315
|
+
f.write(response)
|
|
316
|
+
|
|
317
|
+
return (item_dir.name, len(response), None)
|
|
318
|
+
except Exception as e:
|
|
319
|
+
return (item_dir.name, 0, str(e))
|
|
320
|
+
|
|
321
|
+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
322
|
+
futures = {executor.submit(process_one, item): item for item in to_process}
|
|
323
|
+
|
|
324
|
+
for future in as_completed(futures):
|
|
325
|
+
item_id, chars, error = future.result()
|
|
326
|
+
results.append((item_id, chars, error))
|
|
327
|
+
if error:
|
|
328
|
+
print(f" {item_id}: Error - {error}")
|
|
329
|
+
else:
|
|
330
|
+
print(f" {item_id}: Done ({chars} chars)")
|
|
331
|
+
|
|
332
|
+
print(f"\nProcess complete. {len(results)} items processed.")
|
|
333
|
+
return results
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def call_llm(prompt: str, model: str) -> str:
|
|
337
|
+
"""CUSTOMIZE: Implement your LLM API call here.
|
|
338
|
+
|
|
339
|
+
Use when: sending a single prompt to the LLM and returning the response.
|
|
340
|
+
Replace with actual OpenAI, Anthropic, etc. API calls.
|
|
341
|
+
"""
|
|
342
|
+
# Example mock response - replace with actual API call
|
|
343
|
+
#
|
|
344
|
+
# import anthropic
|
|
345
|
+
# client = anthropic.Anthropic()
|
|
346
|
+
# message = client.messages.create(
|
|
347
|
+
# model=model,
|
|
348
|
+
# max_tokens=1024,
|
|
349
|
+
# messages=[{"role": "user", "content": prompt}],
|
|
350
|
+
# )
|
|
351
|
+
# return message.content[0].text
|
|
352
|
+
|
|
353
|
+
# Simulate API delay
|
|
354
|
+
time.sleep(0.1)
|
|
355
|
+
|
|
356
|
+
# Return mock structured response
|
|
357
|
+
return """## Summary
|
|
358
|
+
This is a sample summary of the analyzed content.
|
|
359
|
+
|
|
360
|
+
## Key Points
|
|
361
|
+
- First key observation from the content
|
|
362
|
+
- Second important finding
|
|
363
|
+
- Third notable aspect
|
|
364
|
+
|
|
365
|
+
## Score
|
|
366
|
+
Rating: 7
|
|
367
|
+
Confidence: medium
|
|
368
|
+
|
|
369
|
+
## Reasoning
|
|
370
|
+
The content demonstrates several characteristics that merit this rating.
|
|
371
|
+
The analysis considered multiple factors including relevance and clarity.
|
|
372
|
+
"""
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
# -----------------------------------------------------------------------------
|
|
376
|
+
# Stage: Parse
|
|
377
|
+
# -----------------------------------------------------------------------------
|
|
378
|
+
|
|
379
|
+
def stage_parse(batch_id: str) -> list[dict[str, Any]]:
|
|
380
|
+
"""Stage 4: Extract structured data from LLM responses.
|
|
381
|
+
|
|
382
|
+
Use when: converting free-text LLM responses into structured
|
|
383
|
+
ParsedResult objects for aggregation and rendering.
|
|
384
|
+
|
|
385
|
+
Output: {batch_dir}/{item_id}/parsed.json
|
|
386
|
+
Returns: List of parsed result dicts with item IDs.
|
|
387
|
+
"""
|
|
388
|
+
batch_dir = get_batch_dir(batch_id)
|
|
389
|
+
all_results: list[dict[str, Any]] = []
|
|
390
|
+
|
|
391
|
+
for item_dir in sorted(batch_dir.iterdir()):
|
|
392
|
+
if not item_dir.is_dir():
|
|
393
|
+
continue
|
|
394
|
+
|
|
395
|
+
response_file = item_dir / "response.md"
|
|
396
|
+
parsed_file = item_dir / "parsed.json"
|
|
397
|
+
|
|
398
|
+
if not response_file.exists():
|
|
399
|
+
continue
|
|
400
|
+
|
|
401
|
+
response = response_file.read_text()
|
|
402
|
+
result = parse_response(response)
|
|
403
|
+
|
|
404
|
+
with open(parsed_file, "w") as f:
|
|
405
|
+
json.dump(asdict(result), f, indent=2)
|
|
406
|
+
|
|
407
|
+
all_results.append({
|
|
408
|
+
"id": item_dir.name,
|
|
409
|
+
**asdict(result),
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
error_count = len(result.parse_errors)
|
|
413
|
+
print(f"Parsed: {item_dir.name} (score={result.score}, errors={error_count})")
|
|
414
|
+
|
|
415
|
+
# Save aggregated results
|
|
416
|
+
agg_file = batch_dir / "all_results.json"
|
|
417
|
+
with open(agg_file, "w") as f:
|
|
418
|
+
json.dump(all_results, f, indent=2)
|
|
419
|
+
|
|
420
|
+
print(f"\nParse complete. Results saved to {agg_file}")
|
|
421
|
+
return all_results
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def parse_response(text: str) -> ParsedResult:
|
|
425
|
+
"""Parse structured LLM response with graceful error handling.
|
|
426
|
+
|
|
427
|
+
Use when: extracting sections, scores, and lists from a formatted
|
|
428
|
+
LLM response. Logs parse errors rather than raising exceptions.
|
|
429
|
+
"""
|
|
430
|
+
result = ParsedResult()
|
|
431
|
+
|
|
432
|
+
# Extract summary
|
|
433
|
+
try:
|
|
434
|
+
result.summary = extract_section(text, "Summary") or ""
|
|
435
|
+
except Exception as e:
|
|
436
|
+
result.parse_errors.append(f"Summary: {e}")
|
|
437
|
+
|
|
438
|
+
# Extract key points
|
|
439
|
+
try:
|
|
440
|
+
result.key_points = extract_list_items(text, "Key Points")
|
|
441
|
+
except Exception as e:
|
|
442
|
+
result.parse_errors.append(f"Key Points: {e}")
|
|
443
|
+
|
|
444
|
+
# Extract score
|
|
445
|
+
try:
|
|
446
|
+
result.score = extract_score(text, "Rating", 1, 10)
|
|
447
|
+
except Exception as e:
|
|
448
|
+
result.parse_errors.append(f"Score: {e}")
|
|
449
|
+
|
|
450
|
+
# Extract confidence
|
|
451
|
+
try:
|
|
452
|
+
result.confidence = extract_field(text, "Confidence") or ""
|
|
453
|
+
except Exception as e:
|
|
454
|
+
result.parse_errors.append(f"Confidence: {e}")
|
|
455
|
+
|
|
456
|
+
# Extract reasoning
|
|
457
|
+
try:
|
|
458
|
+
result.reasoning = extract_section(text, "Reasoning") or ""
|
|
459
|
+
except Exception as e:
|
|
460
|
+
result.parse_errors.append(f"Reasoning: {e}")
|
|
461
|
+
|
|
462
|
+
return result
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def extract_section(text: str, section_name: str) -> str | None:
|
|
466
|
+
"""Extract content between section headers.
|
|
467
|
+
|
|
468
|
+
Use when: pulling a named markdown section from LLM output.
|
|
469
|
+
"""
|
|
470
|
+
pattern = rf'(?:^|\n)(?:#+ *)?{re.escape(section_name)}[:\s]*\n(.*?)(?=\n#|\Z)'
|
|
471
|
+
match = re.search(pattern, text, re.IGNORECASE | re.DOTALL)
|
|
472
|
+
return match.group(1).strip() if match else None
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def extract_field(text: str, field_name: str) -> str | None:
|
|
476
|
+
"""Extract value after field label.
|
|
477
|
+
|
|
478
|
+
Use when: pulling a single key-value field (e.g., "Confidence: high").
|
|
479
|
+
"""
|
|
480
|
+
pattern = rf'(?:\*\*)?{re.escape(field_name)}(?:\*\*)?[\s:\-]+([^\n]+)'
|
|
481
|
+
match = re.search(pattern, text, re.IGNORECASE)
|
|
482
|
+
return match.group(1).strip() if match else None
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def extract_list_items(text: str, section_name: str) -> list[str]:
|
|
486
|
+
"""Extract bullet points from a section.
|
|
487
|
+
|
|
488
|
+
Use when: parsing a markdown list under a named section header.
|
|
489
|
+
"""
|
|
490
|
+
section = extract_section(text, section_name)
|
|
491
|
+
if not section:
|
|
492
|
+
return []
|
|
493
|
+
|
|
494
|
+
items = re.findall(r'^[\-\*]\s*(.+)$', section, re.MULTILINE)
|
|
495
|
+
return [item.strip() for item in items]
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
def extract_score(
|
|
499
|
+
text: str, field_name: str, min_val: int, max_val: int
|
|
500
|
+
) -> int | None:
|
|
501
|
+
"""Extract and validate numeric score.
|
|
502
|
+
|
|
503
|
+
Use when: pulling a bounded integer score from LLM output.
|
|
504
|
+
"""
|
|
505
|
+
raw = extract_field(text, field_name)
|
|
506
|
+
if not raw:
|
|
507
|
+
return None
|
|
508
|
+
|
|
509
|
+
match = re.search(r'\d+', raw)
|
|
510
|
+
if not match:
|
|
511
|
+
return None
|
|
512
|
+
|
|
513
|
+
score = int(match.group())
|
|
514
|
+
return max(min_val, min(max_val, score))
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
# -----------------------------------------------------------------------------
|
|
518
|
+
# Stage: Render
|
|
519
|
+
# -----------------------------------------------------------------------------
|
|
520
|
+
|
|
521
|
+
def stage_render(batch_id: str) -> Path | None:
|
|
522
|
+
"""Stage 5: Generate final outputs from parsed results.
|
|
523
|
+
|
|
524
|
+
Use when: producing human-readable output (HTML, reports)
|
|
525
|
+
from aggregated parsed results.
|
|
526
|
+
|
|
527
|
+
Output: {output_dir}/index.html
|
|
528
|
+
Returns: Path to the rendered output file, or None if no results.
|
|
529
|
+
"""
|
|
530
|
+
batch_dir = get_batch_dir(batch_id)
|
|
531
|
+
output_dir = get_output_dir(batch_id)
|
|
532
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
533
|
+
|
|
534
|
+
# Load aggregated results
|
|
535
|
+
results_file = batch_dir / "all_results.json"
|
|
536
|
+
if not results_file.exists():
|
|
537
|
+
print("No results to render. Run parse stage first.")
|
|
538
|
+
return None
|
|
539
|
+
|
|
540
|
+
with open(results_file) as f:
|
|
541
|
+
results: list[dict[str, Any]] = json.load(f)
|
|
542
|
+
|
|
543
|
+
# CUSTOMIZE: Replace with your rendering logic
|
|
544
|
+
html = render_html(results, batch_id)
|
|
545
|
+
|
|
546
|
+
output_file = output_dir / "index.html"
|
|
547
|
+
with open(output_file, "w") as f:
|
|
548
|
+
f.write(html)
|
|
549
|
+
|
|
550
|
+
print(f"Rendered: {output_file}")
|
|
551
|
+
return output_file
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
def render_html(results: list[dict[str, Any]], batch_id: str) -> str:
|
|
555
|
+
"""Generate HTML output from results.
|
|
556
|
+
|
|
557
|
+
Use when: creating a summary HTML table from parsed pipeline results.
|
|
558
|
+
"""
|
|
559
|
+
import html as html_lib
|
|
560
|
+
|
|
561
|
+
rows = ""
|
|
562
|
+
for r in results:
|
|
563
|
+
rows += f"""
|
|
564
|
+
<tr>
|
|
565
|
+
<td>{html_lib.escape(r.get('id', ''))}</td>
|
|
566
|
+
<td>{html_lib.escape(r.get('summary', '')[:100])}...</td>
|
|
567
|
+
<td>{r.get('score', 'N/A')}</td>
|
|
568
|
+
<td>{html_lib.escape(r.get('confidence', ''))}</td>
|
|
569
|
+
</tr>"""
|
|
570
|
+
|
|
571
|
+
return f"""<!DOCTYPE html>
|
|
572
|
+
<html>
|
|
573
|
+
<head>
|
|
574
|
+
<meta charset="utf-8">
|
|
575
|
+
<title>Results - {batch_id}</title>
|
|
576
|
+
<style>
|
|
577
|
+
body {{ font-family: system-ui, sans-serif; max-width: 1000px; margin: 0 auto; padding: 20px; }}
|
|
578
|
+
table {{ width: 100%; border-collapse: collapse; }}
|
|
579
|
+
th, td {{ text-align: left; padding: 10px; border-bottom: 1px solid #ddd; }}
|
|
580
|
+
th {{ background: #f5f5f5; }}
|
|
581
|
+
</style>
|
|
582
|
+
</head>
|
|
583
|
+
<body>
|
|
584
|
+
<h1>Results: {batch_id}</h1>
|
|
585
|
+
<p>{len(results)} items processed</p>
|
|
586
|
+
<table>
|
|
587
|
+
<tr>
|
|
588
|
+
<th>ID</th>
|
|
589
|
+
<th>Summary</th>
|
|
590
|
+
<th>Score</th>
|
|
591
|
+
<th>Confidence</th>
|
|
592
|
+
</tr>
|
|
593
|
+
{rows}
|
|
594
|
+
</table>
|
|
595
|
+
</body>
|
|
596
|
+
</html>"""
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
# -----------------------------------------------------------------------------
|
|
600
|
+
# Clean Stage
|
|
601
|
+
# -----------------------------------------------------------------------------
|
|
602
|
+
|
|
603
|
+
def stage_clean(batch_id: str, from_stage: str | None = None) -> int:
|
|
604
|
+
"""Remove stage outputs to enable re-processing.
|
|
605
|
+
|
|
606
|
+
Use when: a stage produced bad results and needs to be re-run,
|
|
607
|
+
or when clearing all intermediate files for a fresh pipeline run.
|
|
608
|
+
|
|
609
|
+
Returns: Number of files deleted.
|
|
610
|
+
"""
|
|
611
|
+
batch_dir = get_batch_dir(batch_id)
|
|
612
|
+
|
|
613
|
+
if not batch_dir.exists():
|
|
614
|
+
print(f"No data directory for {batch_id}")
|
|
615
|
+
return 0
|
|
616
|
+
|
|
617
|
+
stage_outputs: dict[str, list[str]] = {
|
|
618
|
+
"acquire": ["raw.json"],
|
|
619
|
+
"prepare": ["prompt.md"],
|
|
620
|
+
"process": ["response.md"],
|
|
621
|
+
"parse": ["parsed.json"],
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
stage_order = ["acquire", "prepare", "process", "parse", "render"]
|
|
625
|
+
|
|
626
|
+
if from_stage:
|
|
627
|
+
start_idx = stage_order.index(from_stage)
|
|
628
|
+
stages_to_clean = stage_order[start_idx:]
|
|
629
|
+
else:
|
|
630
|
+
stages_to_clean = stage_order
|
|
631
|
+
|
|
632
|
+
files_to_delete: set[str] = set()
|
|
633
|
+
for s in stages_to_clean:
|
|
634
|
+
files_to_delete.update(stage_outputs.get(s, []))
|
|
635
|
+
|
|
636
|
+
deleted_count = 0
|
|
637
|
+
for item_dir in batch_dir.iterdir():
|
|
638
|
+
if not item_dir.is_dir():
|
|
639
|
+
continue
|
|
640
|
+
|
|
641
|
+
for filename in files_to_delete:
|
|
642
|
+
filepath = item_dir / filename
|
|
643
|
+
if filepath.exists():
|
|
644
|
+
filepath.unlink()
|
|
645
|
+
deleted_count += 1
|
|
646
|
+
|
|
647
|
+
# Clean aggregated results
|
|
648
|
+
if "parse" in stages_to_clean:
|
|
649
|
+
agg_file = batch_dir / "all_results.json"
|
|
650
|
+
if agg_file.exists():
|
|
651
|
+
agg_file.unlink()
|
|
652
|
+
deleted_count += 1
|
|
653
|
+
|
|
654
|
+
print(f"Cleaned {deleted_count} files from stage '{from_stage or 'all'}' onwards")
|
|
655
|
+
return deleted_count
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
# -----------------------------------------------------------------------------
|
|
659
|
+
# Cost Estimation
|
|
660
|
+
# -----------------------------------------------------------------------------
|
|
661
|
+
|
|
662
|
+
def stage_estimate(batch_id: str) -> dict[str, Any] | None:
|
|
663
|
+
"""Estimate processing costs before running the process stage.
|
|
664
|
+
|
|
665
|
+
Use when: projecting token costs and budget requirements before
|
|
666
|
+
committing to expensive LLM API calls.
|
|
667
|
+
|
|
668
|
+
Returns: Dict with item_count, token estimates, and cost projection,
|
|
669
|
+
or None if no prompts are available.
|
|
670
|
+
"""
|
|
671
|
+
batch_dir = get_batch_dir(batch_id)
|
|
672
|
+
|
|
673
|
+
if not batch_dir.exists():
|
|
674
|
+
print(f"No data directory for {batch_id}. Run acquire first.")
|
|
675
|
+
return None
|
|
676
|
+
|
|
677
|
+
# Count items and estimate tokens
|
|
678
|
+
item_count = 0
|
|
679
|
+
total_prompt_chars = 0
|
|
680
|
+
|
|
681
|
+
for item_dir in batch_dir.iterdir():
|
|
682
|
+
if not item_dir.is_dir():
|
|
683
|
+
continue
|
|
684
|
+
|
|
685
|
+
prompt_file = item_dir / "prompt.md"
|
|
686
|
+
if prompt_file.exists():
|
|
687
|
+
total_prompt_chars += len(prompt_file.read_text())
|
|
688
|
+
item_count += 1
|
|
689
|
+
|
|
690
|
+
if item_count == 0:
|
|
691
|
+
print("No prompts found. Run prepare first.")
|
|
692
|
+
return None
|
|
693
|
+
|
|
694
|
+
# Rough token estimation (1 token ~ 4 chars)
|
|
695
|
+
est_input_tokens = total_prompt_chars / 4
|
|
696
|
+
est_output_tokens = item_count * 500 # Assume 500 tokens per response
|
|
697
|
+
|
|
698
|
+
# Example pricing (adjust for your model)
|
|
699
|
+
input_price = 3.0 / 1_000_000 # $3 per MTok
|
|
700
|
+
output_price = 15.0 / 1_000_000 # $15 per MTok
|
|
701
|
+
|
|
702
|
+
est_cost = (est_input_tokens * input_price) + (est_output_tokens * output_price)
|
|
703
|
+
|
|
704
|
+
estimate: dict[str, Any] = {
|
|
705
|
+
"batch_id": batch_id,
|
|
706
|
+
"item_count": item_count,
|
|
707
|
+
"est_input_tokens": int(est_input_tokens),
|
|
708
|
+
"est_output_tokens": int(est_output_tokens),
|
|
709
|
+
"est_cost_usd": round(est_cost, 2),
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
print(f"Cost Estimate for {batch_id}")
|
|
713
|
+
print(f" Items: {item_count}")
|
|
714
|
+
print(f" Estimated input tokens: {int(est_input_tokens):,}")
|
|
715
|
+
print(f" Estimated output tokens: {int(est_output_tokens):,}")
|
|
716
|
+
print(f" Estimated cost: ${est_cost:.2f}")
|
|
717
|
+
print(f"\nNote: Actual costs may vary. Add 20-30% buffer for retries.")
|
|
718
|
+
|
|
719
|
+
return estimate
|
|
720
|
+
|
|
721
|
+
|
|
722
|
+
# -----------------------------------------------------------------------------
|
|
723
|
+
# CLI
|
|
724
|
+
# -----------------------------------------------------------------------------
|
|
725
|
+
|
|
726
|
+
def main() -> None:
|
|
727
|
+
"""Entry point for CLI usage. Parses arguments and dispatches to stages."""
|
|
728
|
+
parser = argparse.ArgumentParser(
|
|
729
|
+
description="LLM Batch Processing Pipeline",
|
|
730
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
731
|
+
epilog=__doc__,
|
|
732
|
+
)
|
|
733
|
+
|
|
734
|
+
parser.add_argument(
|
|
735
|
+
"stage",
|
|
736
|
+
choices=["acquire", "prepare", "process", "parse", "render", "all", "clean", "estimate"],
|
|
737
|
+
help="Pipeline stage to run",
|
|
738
|
+
)
|
|
739
|
+
parser.add_argument(
|
|
740
|
+
"--batch-id",
|
|
741
|
+
default=None,
|
|
742
|
+
help="Batch identifier (default: today's date)",
|
|
743
|
+
)
|
|
744
|
+
parser.add_argument(
|
|
745
|
+
"--limit",
|
|
746
|
+
type=int,
|
|
747
|
+
default=None,
|
|
748
|
+
help="Limit number of items (for testing)",
|
|
749
|
+
)
|
|
750
|
+
parser.add_argument(
|
|
751
|
+
"--workers",
|
|
752
|
+
type=int,
|
|
753
|
+
default=5,
|
|
754
|
+
help="Number of parallel workers for processing",
|
|
755
|
+
)
|
|
756
|
+
parser.add_argument(
|
|
757
|
+
"--model",
|
|
758
|
+
default="claude-sonnet-4-20250514",
|
|
759
|
+
help="Model to use for processing",
|
|
760
|
+
)
|
|
761
|
+
parser.add_argument(
|
|
762
|
+
"--clean-stage",
|
|
763
|
+
choices=["acquire", "prepare", "process", "parse"],
|
|
764
|
+
help="For clean: only clean this stage and downstream",
|
|
765
|
+
)
|
|
766
|
+
|
|
767
|
+
args = parser.parse_args()
|
|
768
|
+
|
|
769
|
+
batch_id = args.batch_id or date.today().isoformat()
|
|
770
|
+
print(f"Batch ID: {batch_id}\n")
|
|
771
|
+
|
|
772
|
+
if args.stage == "clean":
|
|
773
|
+
stage_clean(batch_id, args.clean_stage)
|
|
774
|
+
elif args.stage == "estimate":
|
|
775
|
+
stage_estimate(batch_id)
|
|
776
|
+
elif args.stage == "all":
|
|
777
|
+
stage_acquire(batch_id, args.limit)
|
|
778
|
+
stage_prepare(batch_id)
|
|
779
|
+
stage_process(batch_id, args.model, args.workers)
|
|
780
|
+
stage_parse(batch_id)
|
|
781
|
+
stage_render(batch_id)
|
|
782
|
+
else:
|
|
783
|
+
if args.stage == "acquire":
|
|
784
|
+
stage_acquire(batch_id, args.limit)
|
|
785
|
+
elif args.stage == "prepare":
|
|
786
|
+
stage_prepare(batch_id)
|
|
787
|
+
elif args.stage == "process":
|
|
788
|
+
stage_process(batch_id, args.model, args.workers)
|
|
789
|
+
elif args.stage == "parse":
|
|
790
|
+
stage_parse(batch_id)
|
|
791
|
+
elif args.stage == "render":
|
|
792
|
+
stage_render(batch_id)
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
if __name__ == "__main__":
|
|
796
|
+
main()
|