pulse-engine 0.2.18__tar.gz → 0.2.19__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/PKG-INFO +1 -1
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/pyproject.toml +1 -1
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/report_generator.py +3 -3
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/reporting/models.py +3 -3
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/reporting/tools.py +3 -1
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/reporting/wiring.py +1 -0
- pulse_engine-0.2.19/src/pulse_engine/skills/seed.py +141 -0
- pulse_engine-0.2.19/src/pulse_engine/skills/seed_data/skill_files.json +975 -0
- pulse_engine-0.2.19/src/pulse_engine/skills/seed_data/skills.json +55 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/README.md +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/audio_transcription.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/batcher.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/digital_news.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/digital_news_metadata.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/exceptions.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/mart_export.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/models.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/opensearch_sql.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/opensearch_storage.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/speech_content.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/speech_metadata.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/transcription/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/transcription/base.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/transcription/config.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/transcription/factory.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/transcription/providers/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/transcription/providers/deepgram.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/transcription/providers/openai_whisper.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/transcription/providers/selfhosted_job.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/transcription/providers/youtube_captions.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/transcription/service.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/transcription/source.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/twitter.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/youtube_downloader.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/adapters/youtube_metadata.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/api/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/api/v1/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/api/v1/auth.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/api/v1/health.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/api/v1/router.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cli/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cli/main.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cli/templates/cookiecutter.json +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/.gitignore +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/Dockerfile +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/pipeline.yaml +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/pyproject.toml +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/src/pulse_{{cookiecutter.product_slug}}/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/tests/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/tests/unit/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cli/templates/pulse-{{cookiecutter.product_name}}/tests/unit/test_manifest.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/client.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/config.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/core/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/core/error_handlers.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/core/exceptions.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/core/job_token.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/core/logging.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/core/scope.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/core/security.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cron/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cron/models.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cron/pipeline_sync.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cron/repository.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cron/router.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cron/runner.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cron/schemas.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cron/service.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cron/tasks.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/cron/translator.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/database.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/dependencies.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/deployment/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/deployment/infra_provisioner.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/evolution/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/evolution/adapter.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/evolution/client.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/evolution/models.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/evolution/router.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/evolution/service.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/extractor/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/extractor/adapters/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/extractor/base.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/main.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/mcp/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/mcp/__main__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/mcp/server.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/mcp/tools_kb.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/mcp/tools_modules.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/mcp/tools_pipelines.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/mcp/tools_processor.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/middleware/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/middleware/rate_limit.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/middleware/request_id.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/middleware/security_headers.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/middleware/tenant.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/notifications/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/notifications/apprise_notifier.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/config_parser.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/expression.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/models.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/repositories.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/router_modules.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/router_pipelines.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/schemas.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/service.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/translators/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/translators/airflow_status.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/translators/airflow_translator.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/translators/base.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/translators/prefect_status.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/pipeline/translators/prefect_translator.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/base.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/core/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/core/analysis.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/core/chunking.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/core/prompts.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/core/topic_splitter.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/defaults/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/defaults/core_processor.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/defaults/postprocessor.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/defaults/preprocessor.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/llm/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/llm/provider.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/ocr/gemini.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/pipeline.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/postprocessor/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/postprocessor/embeddings.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/postprocessor/tasks.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/preprocessor/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/preprocessor/tasks.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/router.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/processor/schemas.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/registry.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/reporting/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/reporting/agent.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/reporting/fixtures.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/reporting/prompts.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/reporting/service.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/runners/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/runners/lambda_runner.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/runners/pipeline_runner.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/runners/prefect_pipeline_flow.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/runners/prefect_runner.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/s3.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/sandbox/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/sandbox/backend.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/sandbox/lambda_microvm.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/sandbox/microvm_agent/Dockerfile +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/sandbox/microvm_agent/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/sandbox/microvm_agent/server.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/sandbox/session.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/secrets.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/services/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/services/bootstrap.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/services/opensearch.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/skills/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/skills/catalog.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/skills/models.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/skills/repo.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/skills/sync.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/skills/tools.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/storage/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/storage/connectors/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/storage/connectors/athena.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/storage/connectors/base.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/storage/connectors/opensearch.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/storage/knowledge_base.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/storage/router.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/storage/schemas.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/testing/__init__.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/testing/fixtures.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/testing/mocks.py +0 -0
- {pulse_engine-0.2.18 → pulse_engine-0.2.19}/src/pulse_engine/worker.py +0 -0
|
@@ -104,9 +104,9 @@ class ReportGeneratorAdapter:
|
|
|
104
104
|
version_number?}) pins a skill; omit it to let the engine's agent auto-select
|
|
105
105
|
from the tenant's active catalog. ``marts`` (list of mart-name stems) restricts
|
|
106
106
|
which staged fixtures the agent may read; omit for all. ``artifact_type``
|
|
107
|
-
(html|pdf|docx|xlsx|pptx) pins the output format; omit to let the agent
|
|
108
|
-
The fixture source is derived from ``tenant_id`` inside the service —
|
|
109
|
-
caller-supplied.
|
|
107
|
+
(html|pdf|docx|xlsx|pptx|md) pins the output format; omit to let the agent
|
|
108
|
+
decide. The fixture source is derived from ``tenant_id`` inside the service —
|
|
109
|
+
never caller-supplied.
|
|
110
110
|
"""
|
|
111
111
|
from pulse_engine.reporting.models import ReportRequest
|
|
112
112
|
|
|
@@ -8,7 +8,7 @@ from typing import Literal
|
|
|
8
8
|
from pydantic import BaseModel, Field, field_validator
|
|
9
9
|
|
|
10
10
|
# The artifact formats the reporting pipeline can emit (mirrors wiring._CONTENT_TYPES).
|
|
11
|
-
ArtifactType = Literal["html", "pdf", "docx", "xlsx", "pptx"]
|
|
11
|
+
ArtifactType = Literal["html", "pdf", "docx", "xlsx", "pptx", "md"]
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class SkillRef(BaseModel):
|
|
@@ -38,7 +38,7 @@ class ReportRequest(BaseModel):
|
|
|
38
38
|
# injected into the kickoff and the run fails if the agent emits a different type.
|
|
39
39
|
artifact_type: ArtifactType | None = Field(
|
|
40
40
|
default=None,
|
|
41
|
-
description="Output format (html|pdf|docx|xlsx|pptx); None = agent decides",
|
|
41
|
+
description="Output format (html|pdf|docx|xlsx|pptx|md); None = agent decides",
|
|
42
42
|
)
|
|
43
43
|
# NOTE: the fixture source is derived server-side from the authenticated tenant
|
|
44
44
|
# (see wiring.make_reader). It is deliberately NOT caller-supplied — accepting a
|
|
@@ -54,7 +54,7 @@ class ReportRequest(BaseModel):
|
|
|
54
54
|
|
|
55
55
|
class ReportResult(BaseModel):
|
|
56
56
|
artifact_url: str
|
|
57
|
-
artifact_type: str # "html" (v1 default) | "pdf" | "docx" | "xlsx" | "pptx"
|
|
57
|
+
artifact_type: str # "html" (v1 default) | "pdf" | "docx" | "xlsx" | "pptx" | "md"
|
|
58
58
|
skill_id: str
|
|
59
59
|
skill_version: int | None
|
|
60
60
|
tokens: int
|
|
@@ -33,7 +33,9 @@ class _WriteReportInput(BaseModel):
|
|
|
33
33
|
path: str = Field(
|
|
34
34
|
..., description="Absolute path of the finished artifact in the sandbox"
|
|
35
35
|
)
|
|
36
|
-
artifact_type: str = Field(
|
|
36
|
+
artifact_type: str = Field(
|
|
37
|
+
"html", description="html | pdf | docx | xlsx | pptx | md"
|
|
38
|
+
)
|
|
37
39
|
|
|
38
40
|
|
|
39
41
|
def build_report_tools(
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""Idempotent seeding of the Agent Skills catalog from captured JSON snapshots.
|
|
2
|
+
|
|
3
|
+
Extracted from Alembic migration ``0017`` (see DD-0xx). The migration only ever
|
|
4
|
+
inserted rows if absent (``ON CONFLICT (id) DO NOTHING``), so once seeded the
|
|
5
|
+
catalog could never be refreshed without authoring a new migration. This seeder
|
|
6
|
+
**upserts** by primary key instead: re-running inserts missing rows and refreshes
|
|
7
|
+
existing ones, so the catalog stays current independently of schema versioning.
|
|
8
|
+
|
|
9
|
+
Schema lives in migration ``0016``; this module owns the data. The catalog is
|
|
10
|
+
reference content, not per-tenant data, so a single global seed is correct.
|
|
11
|
+
|
|
12
|
+
Run it with ``make seed`` or ``python -m pulse_engine.skills.seed``.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Any, cast
|
|
21
|
+
|
|
22
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
23
|
+
|
|
24
|
+
from pulse_engine.skills.models import Skill, SkillFile
|
|
25
|
+
|
|
26
|
+
# Columns each snapshot row carries (mirror migration 0017's table constructs).
|
|
27
|
+
# ``id`` is handled separately as the conflict key; created_at/updated_at are left
|
|
28
|
+
# to their server defaults / onupdate so refreshes never clobber creation time.
|
|
29
|
+
_SKILL_COLS = ("frontmatter", "body_content", "is_active", "visibility")
|
|
30
|
+
_FILE_COLS = ("skill_id", "relative_path", "s3_key", "content_type")
|
|
31
|
+
|
|
32
|
+
DEFAULT_DATA_DIR = Path(__file__).resolve().parent / "seed_data"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class SeedResult:
|
|
37
|
+
"""Counts from one seed run — insufficient to be interesting, handy for logs."""
|
|
38
|
+
|
|
39
|
+
skills_inserted: int = 0
|
|
40
|
+
skills_updated: int = 0
|
|
41
|
+
files_inserted: int = 0
|
|
42
|
+
files_updated: int = 0
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _load(data_dir: Path, name: str) -> list[dict[str, Any]]:
|
|
46
|
+
return cast("list[dict[str, Any]]", json.loads((data_dir / name).read_text()))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
async def _upsert(
|
|
50
|
+
session: AsyncSession,
|
|
51
|
+
model: type[Skill] | type[SkillFile],
|
|
52
|
+
rows: list[dict[str, Any]],
|
|
53
|
+
cols: tuple[str, ...],
|
|
54
|
+
) -> tuple[int, int]:
|
|
55
|
+
"""Insert-or-refresh ``rows`` by primary key; return (inserted, updated).
|
|
56
|
+
|
|
57
|
+
ORM get-then-set rather than a dialect-specific ``ON CONFLICT`` so the same
|
|
58
|
+
path runs on Postgres (prod) and SQLite (tests). The row count (~150) makes
|
|
59
|
+
per-row SELECTs irrelevant to performance. Flushes at the end so a subsequent
|
|
60
|
+
child upsert sees the parents (FK order).
|
|
61
|
+
"""
|
|
62
|
+
inserted = updated = 0
|
|
63
|
+
for row in rows:
|
|
64
|
+
existing = await session.get(model, row["id"])
|
|
65
|
+
if existing is None:
|
|
66
|
+
session.add(model(id=row["id"], **{c: row[c] for c in cols}))
|
|
67
|
+
inserted += 1
|
|
68
|
+
else:
|
|
69
|
+
for c in cols:
|
|
70
|
+
setattr(existing, c, row[c])
|
|
71
|
+
updated += 1
|
|
72
|
+
await session.flush()
|
|
73
|
+
return inserted, updated
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
async def seed_skills(
|
|
77
|
+
session: AsyncSession, *, data_dir: Path = DEFAULT_DATA_DIR
|
|
78
|
+
) -> SeedResult:
|
|
79
|
+
"""Upsert the skills + skill_files catalog. Idempotent; refreshes on re-run.
|
|
80
|
+
|
|
81
|
+
Parents (``skills``) are upserted before children (``skill_files``) to satisfy
|
|
82
|
+
the FK. The caller owns the transaction — commit (or roll back) after this
|
|
83
|
+
returns. ``skill_versions`` is intentionally not seeded (empty at capture).
|
|
84
|
+
"""
|
|
85
|
+
skills_inserted, skills_updated = await _upsert(
|
|
86
|
+
session, Skill, _load(data_dir, "skills.json"), _SKILL_COLS
|
|
87
|
+
)
|
|
88
|
+
files_inserted, files_updated = await _upsert(
|
|
89
|
+
session, SkillFile, _load(data_dir, "skill_files.json"), _FILE_COLS
|
|
90
|
+
)
|
|
91
|
+
return SeedResult(
|
|
92
|
+
skills_inserted=skills_inserted,
|
|
93
|
+
skills_updated=skills_updated,
|
|
94
|
+
files_inserted=files_inserted,
|
|
95
|
+
files_updated=files_updated,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
async def _run(data_dir: Path) -> SeedResult:
|
|
100
|
+
from pulse_engine.config import get_settings
|
|
101
|
+
from pulse_engine.database import build_async_engine, build_session_factory
|
|
102
|
+
|
|
103
|
+
settings = get_settings()
|
|
104
|
+
if not settings.database_url:
|
|
105
|
+
raise SystemExit("DATABASE_URL is required to seed the skills catalog")
|
|
106
|
+
|
|
107
|
+
engine = build_async_engine(settings.database_url)
|
|
108
|
+
try:
|
|
109
|
+
maker = build_session_factory(engine)
|
|
110
|
+
async with maker() as session:
|
|
111
|
+
result = await seed_skills(session, data_dir=data_dir)
|
|
112
|
+
await session.commit()
|
|
113
|
+
return result
|
|
114
|
+
finally:
|
|
115
|
+
await engine.dispose()
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def main() -> None:
|
|
119
|
+
import argparse
|
|
120
|
+
import asyncio
|
|
121
|
+
|
|
122
|
+
parser = argparse.ArgumentParser(
|
|
123
|
+
description="Seed/refresh the Agent Skills catalog (idempotent upsert)"
|
|
124
|
+
)
|
|
125
|
+
parser.add_argument(
|
|
126
|
+
"--data-dir",
|
|
127
|
+
type=Path,
|
|
128
|
+
default=DEFAULT_DATA_DIR,
|
|
129
|
+
help="Directory holding skills.json + skill_files.json "
|
|
130
|
+
f"(default: {DEFAULT_DATA_DIR})",
|
|
131
|
+
)
|
|
132
|
+
args = parser.parse_args()
|
|
133
|
+
result = asyncio.run(_run(args.data_dir))
|
|
134
|
+
print(
|
|
135
|
+
f"skills: +{result.skills_inserted} ~{result.skills_updated} "
|
|
136
|
+
f"skill_files: +{result.files_inserted} ~{result.files_updated}"
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
if __name__ == "__main__":
|
|
141
|
+
main()
|