gatewaysdk 0.3.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gatewaysdk/__init__.py +540 -0
- gatewaysdk/adapter/__init__.py +15 -0
- gatewaysdk/adapter/base.py +94 -0
- gatewaysdk/adapter/messages.py +270 -0
- gatewaysdk/adapter/triplet.py +1026 -0
- gatewaysdk/algorithm/__init__.py +39 -0
- gatewaysdk/algorithm/apo/__init__.py +5 -0
- gatewaysdk/algorithm/apo/apo.py +898 -0
- gatewaysdk/algorithm/apo/prompts/apply_edit_variant01.poml +22 -0
- gatewaysdk/algorithm/apo/prompts/apply_edit_variant02.poml +18 -0
- gatewaysdk/algorithm/apo/prompts/text_gradient_variant01.poml +18 -0
- gatewaysdk/algorithm/apo/prompts/text_gradient_variant02.poml +16 -0
- gatewaysdk/algorithm/apo/prompts/text_gradient_variant03.poml +107 -0
- gatewaysdk/algorithm/base.py +262 -0
- gatewaysdk/algorithm/decorator.py +264 -0
- gatewaysdk/algorithm/evals/__init__.py +7 -0
- gatewaysdk/algorithm/evals/evals.py +217 -0
- gatewaysdk/algorithm/fast.py +250 -0
- gatewaysdk/algorithm/gepa/__init__.py +61 -0
- gatewaysdk/algorithm/gepa/adapter.py +495 -0
- gatewaysdk/algorithm/gepa/gepa.py +570 -0
- gatewaysdk/algorithm/gepa/lib/__init__.py +18 -0
- gatewaysdk/algorithm/gepa/lib/adapters/README.md +12 -0
- gatewaysdk/algorithm/gepa/lib/adapters/__init__.py +0 -0
- gatewaysdk/algorithm/gepa/lib/adapters/anymaths_adapter/README.md +341 -0
- gatewaysdk/algorithm/gepa/lib/adapters/anymaths_adapter/__init__.py +1 -0
- gatewaysdk/algorithm/gepa/lib/adapters/anymaths_adapter/anymaths_adapter.py +174 -0
- gatewaysdk/algorithm/gepa/lib/adapters/anymaths_adapter/requirements.txt +1 -0
- gatewaysdk/algorithm/gepa/lib/adapters/default_adapter/README.md +0 -0
- gatewaysdk/algorithm/gepa/lib/adapters/default_adapter/__init__.py +0 -0
- gatewaysdk/algorithm/gepa/lib/adapters/default_adapter/default_adapter.py +209 -0
- gatewaysdk/algorithm/gepa/lib/adapters/dspy_adapter/README.md +7 -0
- gatewaysdk/algorithm/gepa/lib/adapters/dspy_adapter/__init__.py +0 -0
- gatewaysdk/algorithm/gepa/lib/adapters/dspy_adapter/dspy_adapter.py +307 -0
- gatewaysdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/README.md +99 -0
- gatewaysdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/dspy_program_proposal_signature.py +137 -0
- gatewaysdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/full_program_adapter.py +268 -0
- gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/GEPA_RAG.md +621 -0
- gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/__init__.py +56 -0
- gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/evaluation_metrics.py +226 -0
- gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/generic_rag_adapter.py +496 -0
- gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/rag_pipeline.py +238 -0
- gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_store_interface.py +212 -0
- gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/__init__.py +2 -0
- gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/chroma_store.py +196 -0
- gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/lancedb_store.py +422 -0
- gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/milvus_store.py +409 -0
- gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/qdrant_store.py +368 -0
- gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/weaviate_store.py +418 -0
- gatewaysdk/algorithm/gepa/lib/adapters/mcp_adapter/README.md +552 -0
- gatewaysdk/algorithm/gepa/lib/adapters/mcp_adapter/__init__.py +37 -0
- gatewaysdk/algorithm/gepa/lib/adapters/mcp_adapter/mcp_adapter.py +699 -0
- gatewaysdk/algorithm/gepa/lib/adapters/mcp_adapter/mcp_client.py +364 -0
- gatewaysdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/README.md +9 -0
- gatewaysdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/__init__.py +0 -0
- gatewaysdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/terminal_bench_adapter.py +217 -0
- gatewaysdk/algorithm/gepa/lib/api.py +382 -0
- gatewaysdk/algorithm/gepa/lib/core/__init__.py +0 -0
- gatewaysdk/algorithm/gepa/lib/core/adapter.py +180 -0
- gatewaysdk/algorithm/gepa/lib/core/data_loader.py +74 -0
- gatewaysdk/algorithm/gepa/lib/core/engine.py +379 -0
- gatewaysdk/algorithm/gepa/lib/core/result.py +233 -0
- gatewaysdk/algorithm/gepa/lib/core/state.py +636 -0
- gatewaysdk/algorithm/gepa/lib/examples/__init__.py +0 -0
- gatewaysdk/algorithm/gepa/lib/examples/aime.py +24 -0
- gatewaysdk/algorithm/gepa/lib/examples/anymaths-bench/eval_default.py +111 -0
- gatewaysdk/algorithm/gepa/lib/examples/anymaths-bench/prompt-templates/instruction_prompt.txt +9 -0
- gatewaysdk/algorithm/gepa/lib/examples/anymaths-bench/prompt-templates/optimal_prompt.txt +24 -0
- gatewaysdk/algorithm/gepa/lib/examples/anymaths-bench/train_anymaths.py +177 -0
- gatewaysdk/algorithm/gepa/lib/examples/dspy_full_program_evolution/arc_agi.ipynb +25705 -0
- gatewaysdk/algorithm/gepa/lib/examples/dspy_full_program_evolution/example.ipynb +348 -0
- gatewaysdk/algorithm/gepa/lib/examples/mcp_adapter/__init__.py +4 -0
- gatewaysdk/algorithm/gepa/lib/examples/mcp_adapter/mcp_optimization_example.py +456 -0
- gatewaysdk/algorithm/gepa/lib/examples/rag_adapter/RAG_GUIDE.md +613 -0
- gatewaysdk/algorithm/gepa/lib/examples/rag_adapter/__init__.py +9 -0
- gatewaysdk/algorithm/gepa/lib/examples/rag_adapter/rag_optimization.py +820 -0
- gatewaysdk/algorithm/gepa/lib/examples/rag_adapter/requirements-rag.txt +29 -0
- gatewaysdk/algorithm/gepa/lib/examples/terminal-bench/prompt-templates/instruction_prompt.txt +16 -0
- gatewaysdk/algorithm/gepa/lib/examples/terminal-bench/prompt-templates/terminus.txt +9 -0
- gatewaysdk/algorithm/gepa/lib/examples/terminal-bench/train_terminus.py +161 -0
- gatewaysdk/algorithm/gepa/lib/gepa_utils.py +117 -0
- gatewaysdk/algorithm/gepa/lib/logging/__init__.py +0 -0
- gatewaysdk/algorithm/gepa/lib/logging/experiment_tracker.py +187 -0
- gatewaysdk/algorithm/gepa/lib/logging/logger.py +75 -0
- gatewaysdk/algorithm/gepa/lib/logging/utils.py +103 -0
- gatewaysdk/algorithm/gepa/lib/proposer/__init__.py +0 -0
- gatewaysdk/algorithm/gepa/lib/proposer/base.py +31 -0
- gatewaysdk/algorithm/gepa/lib/proposer/merge.py +357 -0
- gatewaysdk/algorithm/gepa/lib/proposer/reflective_mutation/__init__.py +0 -0
- gatewaysdk/algorithm/gepa/lib/proposer/reflective_mutation/base.py +49 -0
- gatewaysdk/algorithm/gepa/lib/proposer/reflective_mutation/reflective_mutation.py +176 -0
- gatewaysdk/algorithm/gepa/lib/py.typed +0 -0
- gatewaysdk/algorithm/gepa/lib/strategies/__init__.py +0 -0
- gatewaysdk/algorithm/gepa/lib/strategies/batch_sampler.py +77 -0
- gatewaysdk/algorithm/gepa/lib/strategies/candidate_selector.py +50 -0
- gatewaysdk/algorithm/gepa/lib/strategies/component_selector.py +36 -0
- gatewaysdk/algorithm/gepa/lib/strategies/eval_policy.py +64 -0
- gatewaysdk/algorithm/gepa/lib/strategies/instruction_proposal.py +126 -0
- gatewaysdk/algorithm/gepa/lib/utils/__init__.py +10 -0
- gatewaysdk/algorithm/gepa/lib/utils/stop_condition.py +196 -0
- gatewaysdk/algorithm/gepa/tracing.py +105 -0
- gatewaysdk/algorithm/utils.py +177 -0
- gatewaysdk/algorithm/verl/__init__.py +5 -0
- gatewaysdk/algorithm/verl/interface.py +202 -0
- gatewaysdk/automations.py +111 -0
- gatewaysdk/benchmark_hub/README.md +88 -0
- gatewaysdk/benchmark_hub/__init__.py +119 -0
- gatewaysdk/benchmark_hub/_archive.py +189 -0
- gatewaysdk/benchmark_hub/_tar.py +6 -0
- gatewaysdk/benchmark_hub/client.py +992 -0
- gatewaysdk/benchmark_hub/dispatch_shard.py +34 -0
- gatewaysdk/benchmark_hub/eval_config.py +20 -0
- gatewaysdk/benchmark_hub/evals.py +351 -0
- gatewaysdk/benchmark_hub/harbor_adapter.py +673 -0
- gatewaysdk/benchmark_hub/path_utils.py +81 -0
- gatewaysdk/benchmark_hub/save_utils.py +101 -0
- gatewaysdk/benchmark_hub/verifiers_adapter.py +327 -0
- gatewaysdk/benchmark_hub/versioning.py +72 -0
- gatewaysdk/build.py +515 -0
- gatewaysdk/cli/__init__.py +58 -0
- gatewaysdk/cli/agent_runner.py +132 -0
- gatewaysdk/cli/http_client.py +115 -0
- gatewaysdk/cli/platform.py +4086 -0
- gatewaysdk/cli/prometheus.py +115 -0
- gatewaysdk/cli/release_gate.py +215 -0
- gatewaysdk/cli/store.py +131 -0
- gatewaysdk/cli/vllm.py +29 -0
- gatewaysdk/client.py +406 -0
- gatewaysdk/config.py +348 -0
- gatewaysdk/connectors/__init__.py +25 -0
- gatewaysdk/connectors/client.py +203 -0
- gatewaysdk/connectors/skill.py +25 -0
- gatewaysdk/connectors/template.py +106 -0
- gatewaysdk/context.py +606 -0
- gatewaysdk/emitter/__init__.py +43 -0
- gatewaysdk/emitter/annotation.py +370 -0
- gatewaysdk/emitter/exception.py +54 -0
- gatewaysdk/emitter/message.py +61 -0
- gatewaysdk/emitter/object.py +117 -0
- gatewaysdk/emitter/reward.py +320 -0
- gatewaysdk/env_var.py +156 -0
- gatewaysdk/environment/__init__.py +108 -0
- gatewaysdk/environment/_bundle.py +281 -0
- gatewaysdk/environment/_harbor.py +276 -0
- gatewaysdk/environment/_materialize.py +97 -0
- gatewaysdk/environment/_tar.py +33 -0
- gatewaysdk/environment/_world.py +346 -0
- gatewaysdk/environment/core.py +527 -0
- gatewaysdk/environment/errors.py +58 -0
- gatewaysdk/environment/runtime.py +150 -0
- gatewaysdk/environment/schema/__init__.py +35 -0
- gatewaysdk/environment/schema/__main__.py +225 -0
- gatewaysdk/environment/schema/_slack_fidelity.py +116 -0
- gatewaysdk/environment/schema/_slack_scenario.py +183 -0
- gatewaysdk/environment/schema/api.py +1628 -0
- gatewaysdk/environment/schema/batch.py +755 -0
- gatewaysdk/environment/schema/compiler.py +615 -0
- gatewaysdk/environment/schema/conform.py +428 -0
- gatewaysdk/environment/schema/connector.py +777 -0
- gatewaysdk/environment/schema/connectors/apple-business-manager/handlers.py +17 -0
- gatewaysdk/environment/schema/connectors/apple-business-manager/parity.json +28 -0
- gatewaysdk/environment/schema/connectors/apple-business-manager/provenance.json +233 -0
- gatewaysdk/environment/schema/connectors/apple-business-manager/scope.toml +112 -0
- gatewaysdk/environment/schema/connectors/apple-business-manager/world.json +1380 -0
- gatewaysdk/environment/schema/connectors/base.json +28 -0
- gatewaysdk/environment/schema/connectors/custom/handlers.py +18 -0
- gatewaysdk/environment/schema/connectors/custom/world.json +123 -0
- gatewaysdk/environment/schema/connectors/github/handlers.py +81 -0
- gatewaysdk/environment/schema/connectors/github/parity.json +37 -0
- gatewaysdk/environment/schema/connectors/github/provenance.json +134 -0
- gatewaysdk/environment/schema/connectors/github/scope.toml +158 -0
- gatewaysdk/environment/schema/connectors/github/world.json +5869 -0
- gatewaysdk/environment/schema/connectors/google-calendar/handlers.py +23 -0
- gatewaysdk/environment/schema/connectors/google-calendar/world.json +209 -0
- gatewaysdk/environment/schema/connectors/google-drive/handlers.py +18 -0
- gatewaysdk/environment/schema/connectors/google-drive/world.json +286 -0
- gatewaysdk/environment/schema/connectors/jamf/handlers.py +34 -0
- gatewaysdk/environment/schema/connectors/jamf/parity.json +49 -0
- gatewaysdk/environment/schema/connectors/jamf/provenance.json +181 -0
- gatewaysdk/environment/schema/connectors/jamf/scope.toml +128 -0
- gatewaysdk/environment/schema/connectors/jamf/world.json +2218 -0
- gatewaysdk/environment/schema/connectors/jira/handlers.py +28 -0
- gatewaysdk/environment/schema/connectors/jira/world.json +389 -0
- gatewaysdk/environment/schema/connectors/kandji/handlers.py +38 -0
- gatewaysdk/environment/schema/connectors/kandji/parity.json +29 -0
- gatewaysdk/environment/schema/connectors/kandji/provenance.json +152 -0
- gatewaysdk/environment/schema/connectors/kandji/scope.toml +120 -0
- gatewaysdk/environment/schema/connectors/kandji/world.json +765 -0
- gatewaysdk/environment/schema/connectors/linear/handlers.py +20 -0
- gatewaysdk/environment/schema/connectors/linear/world.json +363 -0
- gatewaysdk/environment/schema/connectors/microsoft-teams/fidelity.json +45 -0
- gatewaysdk/environment/schema/connectors/microsoft-teams/handlers.py +1 -0
- gatewaysdk/environment/schema/connectors/microsoft-teams/provenance.json +851 -0
- gatewaysdk/environment/schema/connectors/microsoft-teams/scope.md +231 -0
- gatewaysdk/environment/schema/connectors/microsoft-teams/teams-types.json +1710 -0
- gatewaysdk/environment/schema/connectors/microsoft-teams/world.json +858 -0
- gatewaysdk/environment/schema/connectors/netsuite/handlers.py +32 -0
- gatewaysdk/environment/schema/connectors/netsuite/parity.json +50 -0
- gatewaysdk/environment/schema/connectors/netsuite/provenance.json +137 -0
- gatewaysdk/environment/schema/connectors/netsuite/scope.toml +78 -0
- gatewaysdk/environment/schema/connectors/netsuite/world.json +16243 -0
- gatewaysdk/environment/schema/connectors/salesforce/handlers.py +806 -0
- gatewaysdk/environment/schema/connectors/salesforce/parity.json +46 -0
- gatewaysdk/environment/schema/connectors/salesforce/provenance.json +143 -0
- gatewaysdk/environment/schema/connectors/salesforce/scope.toml +174 -0
- gatewaysdk/environment/schema/connectors/salesforce/world.json +4695 -0
- gatewaysdk/environment/schema/connectors/slack/MODEL.md +236 -0
- gatewaysdk/environment/schema/connectors/slack/capabilities.json +1039 -0
- gatewaysdk/environment/schema/connectors/slack/handlers.py +762 -0
- gatewaysdk/environment/schema/connectors/slack/parity.json +65 -0
- gatewaysdk/environment/schema/connectors/slack/provenance.json +294 -0
- gatewaysdk/environment/schema/connectors/slack/scope.toml +44 -0
- gatewaysdk/environment/schema/connectors/slack/world.json +4993 -0
- gatewaysdk/environment/schema/connectors/workday/handlers.py +75 -0
- gatewaysdk/environment/schema/connectors/workday/parity.json +36 -0
- gatewaysdk/environment/schema/connectors/workday/provenance.json +179 -0
- gatewaysdk/environment/schema/connectors/workday/scope.toml +180 -0
- gatewaysdk/environment/schema/connectors/workday/world.json +806 -0
- gatewaysdk/environment/schema/data.py +593 -0
- gatewaysdk/environment/schema/extract.py +263 -0
- gatewaysdk/environment/schema/host.py +2437 -0
- gatewaysdk/environment/schema/host_surfaces.py +275 -0
- gatewaysdk/environment/schema/platform.py +1272 -0
- gatewaysdk/environment/schema/scaffold.py +250 -0
- gatewaysdk/environment/schema/skill.py +118 -0
- gatewaysdk/environment/schema/skills/agents/connector-template-author.md +202 -0
- gatewaysdk/environment/schema/skills/connector-schema-authoring/CONNECTORS.md +331 -0
- gatewaysdk/environment/schema/skills/connector-schema-authoring/CONVENTIONS.md +100 -0
- gatewaysdk/environment/schema/skills/connector-schema-authoring/SKILL.md +313 -0
- gatewaysdk/environment/schema/skills/world-data-ingestion/ROWS.md +223 -0
- gatewaysdk/environment/schema/skills/world-data-ingestion/SKILL.md +293 -0
- gatewaysdk/environment/schema/skills/worlds-getting-started/SKILL.md +390 -0
- gatewaysdk/environment/schema/slack.py +757 -0
- gatewaysdk/environment/schema/snapshot.py +479 -0
- gatewaysdk/environment/schema/store.py +904 -0
- gatewaysdk/environment/schema/tasks.py +525 -0
- gatewaysdk/environment/schema/tools_world.py +322 -0
- gatewaysdk/environment/schema/validation.py +577 -0
- gatewaysdk/environment/schema/worker.py +78 -0
- gatewaysdk/environment/schema/workers.py +500 -0
- gatewaysdk/environment/schema/world_tests.py +336 -0
- gatewaysdk/environments/__init__.py +24 -0
- gatewaysdk/environments/client.py +486 -0
- gatewaysdk/environments/types.py +318 -0
- gatewaysdk/execution/__init__.py +15 -0
- gatewaysdk/execution/base.py +64 -0
- gatewaysdk/execution/client_server.py +443 -0
- gatewaysdk/execution/events.py +69 -0
- gatewaysdk/execution/inter_process.py +16 -0
- gatewaysdk/execution/shared_memory.py +282 -0
- gatewaysdk/experiments/__init__.py +90 -0
- gatewaysdk/experiments/assignment.py +177 -0
- gatewaysdk/experiments/client.py +877 -0
- gatewaysdk/experiments/exposure.py +222 -0
- gatewaysdk/experiments/types.py +81 -0
- gatewaysdk/importers/__init__.py +49 -0
- gatewaysdk/importers/_normalize.py +91 -0
- gatewaysdk/importers/builder.py +173 -0
- gatewaysdk/importers/client.py +95 -0
- gatewaysdk/importers/langsmith.py +196 -0
- gatewaysdk/importers/recipes.py +249 -0
- gatewaysdk/instrumentation/__init__.py +300 -0
- gatewaysdk/instrumentation/agentops.py +314 -0
- gatewaysdk/instrumentation/agentops_langchain.py +45 -0
- gatewaysdk/instrumentation/base.py +119 -0
- gatewaysdk/instrumentation/litellm.py +83 -0
- gatewaysdk/instrumentation/registry.py +273 -0
- gatewaysdk/instrumentation/vllm.py +81 -0
- gatewaysdk/instrumentation/weave.py +500 -0
- gatewaysdk/integrations/__init__.py +15 -0
- gatewaysdk/integrations/gateway/__init__.py +11 -0
- gatewaysdk/integrations/gateway/client.py +171 -0
- gatewaysdk/integrations/tool_access.py +549 -0
- gatewaysdk/litagent/__init__.py +11 -0
- gatewaysdk/litagent/decorator.py +536 -0
- gatewaysdk/litagent/litagent.py +252 -0
- gatewaysdk/llm_proxy.py +1742 -0
- gatewaysdk/logging.py +370 -0
- gatewaysdk/memory.py +278 -0
- gatewaysdk/personas.py +186 -0
- gatewaysdk/platform/__init__.py +17 -0
- gatewaysdk/platform/builder.py +221 -0
- gatewaysdk/platform/compatibility.py +67 -0
- gatewaysdk/platform/manifest.py +185 -0
- gatewaysdk/platform/orchestrator.py +901 -0
- gatewaysdk/platform/registry.py +122 -0
- gatewaysdk/platform/worker.py +864 -0
- gatewaysdk/replay/__init__.py +1032 -0
- gatewaysdk/replay/pytest.py +56 -0
- gatewaysdk/reward.py +7 -0
- gatewaysdk/run.py +1781 -0
- gatewaysdk/runner/__init__.py +11 -0
- gatewaysdk/runner/agent.py +878 -0
- gatewaysdk/runner/base.py +182 -0
- gatewaysdk/runner/legacy.py +309 -0
- gatewaysdk/security.py +700 -0
- gatewaysdk/semconv.py +170 -0
- gatewaysdk/server.py +399 -0
- gatewaysdk/sessions.py +282 -0
- gatewaysdk/store/__init__.py +45 -0
- gatewaysdk/store/base.py +908 -0
- gatewaysdk/store/client_server.py +2093 -0
- gatewaysdk/store/collection/__init__.py +30 -0
- gatewaysdk/store/collection/base.py +587 -0
- gatewaysdk/store/collection/memory.py +970 -0
- gatewaysdk/store/collection/mongo.py +1412 -0
- gatewaysdk/store/collection_based.py +1823 -0
- gatewaysdk/store/gateway.py +983 -0
- gatewaysdk/store/gateway_listener.py +465 -0
- gatewaysdk/store/listener.py +58 -0
- gatewaysdk/store/memory.py +396 -0
- gatewaysdk/store/mongo.py +165 -0
- gatewaysdk/store/redis_stream.py +517 -0
- gatewaysdk/store/sqlite.py +3 -0
- gatewaysdk/store/threading.py +370 -0
- gatewaysdk/store/utils.py +142 -0
- gatewaysdk/tracer/__init__.py +14 -0
- gatewaysdk/tracer/base.py +286 -0
- gatewaysdk/tracer/dummy.py +106 -0
- gatewaysdk/tracer/otel.py +559 -0
- gatewaysdk/tracing/__init__.py +110 -0
- gatewaysdk/tracing/api.py +808 -0
- gatewaysdk/tracing/attributes.py +9 -0
- gatewaysdk/tracing/context.py +272 -0
- gatewaysdk/tracing/exporters/__init__.py +10 -0
- gatewaysdk/tracing/exporters/gateway.py +228 -0
- gatewaysdk/tracing/identity.py +288 -0
- gatewaysdk/tracing/init.py +620 -0
- gatewaysdk/tracing/instrumentors/__init__.py +15 -0
- gatewaysdk/tracing/instrumentors/claude_agent_sdk.py +766 -0
- gatewaysdk/tracing/instrumentors/instrumentation_principles.md +294 -0
- gatewaysdk/tracing/instrumentors/registry.py +352 -0
- gatewaysdk/tracing/mapping.py +729 -0
- gatewaysdk/tracing/processors.py +393 -0
- gatewaysdk/tracing/push.py +617 -0
- gatewaysdk/tracing/push_models.py +247 -0
- gatewaysdk/tracing/semconv.py +294 -0
- gatewaysdk/tracing/span_builder.py +356 -0
- gatewaysdk/trainer/__init__.py +6 -0
- gatewaysdk/trainer/init_utils.py +263 -0
- gatewaysdk/trainer/legacy.py +359 -0
- gatewaysdk/trainer/registry.py +12 -0
- gatewaysdk/trainer/trainer.py +638 -0
- gatewaysdk/types/__init__.py +63 -0
- gatewaysdk/types/core.py +556 -0
- gatewaysdk/types/resources.py +204 -0
- gatewaysdk/types/tracer.py +515 -0
- gatewaysdk/types/tracing.py +162 -0
- gatewaysdk/users.py +251 -0
- gatewaysdk/utils/__init__.py +1 -0
- gatewaysdk/utils/id.py +18 -0
- gatewaysdk/utils/metrics.py +1025 -0
- gatewaysdk/utils/otel.py +550 -0
- gatewaysdk/utils/otlp.py +556 -0
- gatewaysdk/utils/redact.py +22 -0
- gatewaysdk/utils/server_launcher.py +1045 -0
- gatewaysdk/utils/system_snapshot.py +90 -0
- gatewaysdk/verl/__init__.py +8 -0
- gatewaysdk/verl/__main__.py +6 -0
- gatewaysdk/verl/async_server.py +46 -0
- gatewaysdk/verl/config.yaml +27 -0
- gatewaysdk/verl/daemon.py +1154 -0
- gatewaysdk/verl/dataset.py +44 -0
- gatewaysdk/verl/entrypoint.py +248 -0
- gatewaysdk/verl/trainer.py +549 -0
- gatewaysdk/world_browser.py +748 -0
- gatewaysdk/world_data.py +453 -0
- gatewaysdk/world_sessions.py +978 -0
- gatewaysdk/world_tasks.py +285 -0
- gatewaysdk/world_tools.py +115 -0
- gatewaysdk/worlds.py +639 -0
- gatewaysdk-0.3.2.dist-info/METADATA +236 -0
- gatewaysdk-0.3.2.dist-info/RECORD +376 -0
- gatewaysdk-0.3.2.dist-info/WHEEL +4 -0
- gatewaysdk-0.3.2.dist-info/entry_points.txt +5 -0
- gatewaysdk-0.3.2.dist-info/licenses/LICENSE +19 -0
|
@@ -0,0 +1,729 @@
|
|
|
1
|
+
# Copyright (c) Gateway. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Mapping engine for JSON push-to-trace.
|
|
4
|
+
|
|
5
|
+
Pure data transformation -- no OTel dependency. Handles:
|
|
6
|
+
- Dot-path resolution through nested dicts
|
|
7
|
+
- Convention-based auto-detection (snake_case + camelCase)
|
|
8
|
+
- Dict-to-TraceMapping normalization
|
|
9
|
+
- Field merge strategy (explicit > mapped > context > defaults)
|
|
10
|
+
- Timestamp coercion to nanoseconds
|
|
11
|
+
- Mapping validation with structured errors
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import re
|
|
18
|
+
from datetime import datetime, timezone
|
|
19
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
20
|
+
|
|
21
|
+
from .push_models import (
|
|
22
|
+
ChildMapping,
|
|
23
|
+
TraceMapping,
|
|
24
|
+
ValidationIssue,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# =============================================================================
|
|
28
|
+
# Convention Tables
|
|
29
|
+
# =============================================================================
|
|
30
|
+
|
|
31
|
+
# Each list is checked in order; first match wins.
|
|
32
|
+
# Both snake_case and camelCase variants are included.
|
|
33
|
+
|
|
34
|
+
TRACE_NAME_KEYS = [
|
|
35
|
+
"name",
|
|
36
|
+
"trace_name",
|
|
37
|
+
"traceName",
|
|
38
|
+
"agent_name",
|
|
39
|
+
"agentName",
|
|
40
|
+
"task_name",
|
|
41
|
+
"taskName",
|
|
42
|
+
"workflow_name",
|
|
43
|
+
"workflowName",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
TRACE_INPUT_KEYS = [
|
|
47
|
+
"input",
|
|
48
|
+
"query",
|
|
49
|
+
"question",
|
|
50
|
+
"prompt",
|
|
51
|
+
"request",
|
|
52
|
+
"user_input",
|
|
53
|
+
"userInput",
|
|
54
|
+
"user_message",
|
|
55
|
+
"userMessage",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
TRACE_OUTPUT_KEYS = [
|
|
59
|
+
"output",
|
|
60
|
+
"result",
|
|
61
|
+
"answer",
|
|
62
|
+
"response",
|
|
63
|
+
"completion",
|
|
64
|
+
"final_answer",
|
|
65
|
+
"finalAnswer",
|
|
66
|
+
"agent_output",
|
|
67
|
+
"agentOutput",
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
TRACE_METADATA_KEYS = [
|
|
71
|
+
"metadata",
|
|
72
|
+
"config",
|
|
73
|
+
"configuration",
|
|
74
|
+
"params",
|
|
75
|
+
"parameters",
|
|
76
|
+
"context",
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
TRACE_TAGS_KEYS = ["tags", "labels", "categories"]
|
|
80
|
+
|
|
81
|
+
TRACE_SESSION_ID_KEYS = [
|
|
82
|
+
"session_id",
|
|
83
|
+
"sessionId",
|
|
84
|
+
"session",
|
|
85
|
+
"conversation_id",
|
|
86
|
+
"conversationId",
|
|
87
|
+
"thread_id",
|
|
88
|
+
"threadId",
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
TRACE_USER_ID_KEYS = [
|
|
92
|
+
"user_id",
|
|
93
|
+
"userId",
|
|
94
|
+
"user",
|
|
95
|
+
"author",
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
TRACE_TIMESTAMP_KEYS = [
|
|
99
|
+
"timestamp",
|
|
100
|
+
"created_at",
|
|
101
|
+
"createdAt",
|
|
102
|
+
"start_time",
|
|
103
|
+
"startTime",
|
|
104
|
+
"time",
|
|
105
|
+
"ts",
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
CHILDREN_KEYS = [
|
|
109
|
+
"steps",
|
|
110
|
+
"spans",
|
|
111
|
+
"observations",
|
|
112
|
+
"events",
|
|
113
|
+
"actions",
|
|
114
|
+
"calls",
|
|
115
|
+
"messages",
|
|
116
|
+
"tool_calls",
|
|
117
|
+
"toolCalls",
|
|
118
|
+
"children",
|
|
119
|
+
"traces",
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
# Per-child conventions (in addition to the trace-level ones above)
|
|
123
|
+
CHILD_TYPE_KEYS = [
|
|
124
|
+
"type",
|
|
125
|
+
"kind",
|
|
126
|
+
"span_kind",
|
|
127
|
+
"spanKind",
|
|
128
|
+
"observation_type",
|
|
129
|
+
"observationType",
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
CHILD_MODEL_KEYS = [
|
|
133
|
+
"model",
|
|
134
|
+
"model_name",
|
|
135
|
+
"modelName",
|
|
136
|
+
"llm",
|
|
137
|
+
"model_id",
|
|
138
|
+
"modelId",
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
CHILD_START_TIME_KEYS = [
|
|
142
|
+
"start_time",
|
|
143
|
+
"startTime",
|
|
144
|
+
"started_at",
|
|
145
|
+
"startedAt",
|
|
146
|
+
"timestamp",
|
|
147
|
+
"begin",
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
CHILD_END_TIME_KEYS = [
|
|
151
|
+
"end_time",
|
|
152
|
+
"endTime",
|
|
153
|
+
"ended_at",
|
|
154
|
+
"endedAt",
|
|
155
|
+
"finished_at",
|
|
156
|
+
"finishedAt",
|
|
157
|
+
"completed_at",
|
|
158
|
+
"completedAt",
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
CHILD_LEVEL_KEYS = ["level", "severity", "status"]
|
|
162
|
+
|
|
163
|
+
# Trace-level convention map: target_field -> candidate keys
|
|
164
|
+
TRACE_CONVENTIONS = {
|
|
165
|
+
"name": TRACE_NAME_KEYS,
|
|
166
|
+
"input": TRACE_INPUT_KEYS,
|
|
167
|
+
"output": TRACE_OUTPUT_KEYS,
|
|
168
|
+
"metadata": TRACE_METADATA_KEYS,
|
|
169
|
+
"tags": TRACE_TAGS_KEYS,
|
|
170
|
+
"session_id": TRACE_SESSION_ID_KEYS,
|
|
171
|
+
"user_id": TRACE_USER_ID_KEYS,
|
|
172
|
+
"timestamp": TRACE_TIMESTAMP_KEYS,
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
# Child-level convention map (extends trace-level for shared fields)
|
|
176
|
+
CHILD_CONVENTIONS = {
|
|
177
|
+
"name": TRACE_NAME_KEYS,
|
|
178
|
+
"input": TRACE_INPUT_KEYS,
|
|
179
|
+
"output": TRACE_OUTPUT_KEYS,
|
|
180
|
+
"metadata": TRACE_METADATA_KEYS,
|
|
181
|
+
"type": CHILD_TYPE_KEYS,
|
|
182
|
+
"model": CHILD_MODEL_KEYS,
|
|
183
|
+
"start_time": CHILD_START_TIME_KEYS,
|
|
184
|
+
"end_time": CHILD_END_TIME_KEYS,
|
|
185
|
+
"level": CHILD_LEVEL_KEYS,
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# =============================================================================
|
|
190
|
+
# Path Resolution
|
|
191
|
+
# =============================================================================
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def resolve_path(data: dict, dot_path: str) -> Tuple[bool, Any]:
|
|
195
|
+
"""Navigate a dot-path string through nested dicts.
|
|
196
|
+
|
|
197
|
+
Returns (found, value). Does not raise on missing keys.
|
|
198
|
+
|
|
199
|
+
Examples::
|
|
200
|
+
|
|
201
|
+
resolve_path({"a": {"b": 1}}, "a.b") -> (True, 1)
|
|
202
|
+
resolve_path({"a": 1}, "a.b.c") -> (False, None)
|
|
203
|
+
"""
|
|
204
|
+
current = data
|
|
205
|
+
for key in dot_path.split("."):
|
|
206
|
+
if isinstance(current, dict) and key in current:
|
|
207
|
+
current = current[key]
|
|
208
|
+
else:
|
|
209
|
+
return False, None
|
|
210
|
+
return True, current
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
# =============================================================================
|
|
214
|
+
# Convention Detection
|
|
215
|
+
# =============================================================================
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _find_convention_match(data: dict, candidate_keys: List[str]) -> Optional[str]:
|
|
219
|
+
"""Find the first candidate key that exists in data (case-insensitive)."""
|
|
220
|
+
data_keys_lower = {k.lower(): k for k in data.keys()}
|
|
221
|
+
for candidate in candidate_keys:
|
|
222
|
+
actual_key = data_keys_lower.get(candidate.lower())
|
|
223
|
+
if actual_key is not None:
|
|
224
|
+
return actual_key
|
|
225
|
+
return None
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def apply_conventions(data: dict, depth: Optional[int] = 1) -> TraceMapping:
|
|
229
|
+
"""Scan JSON keys for convention matches and return a TraceMapping.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
data: The JSON dict to scan.
|
|
233
|
+
depth: How deep to recurse for children conventions.
|
|
234
|
+
0 = trace-level only, 1 = one level of children, None = unlimited.
|
|
235
|
+
"""
|
|
236
|
+
kwargs: Dict[str, Any] = {}
|
|
237
|
+
|
|
238
|
+
for target, candidates in TRACE_CONVENTIONS.items():
|
|
239
|
+
match = _find_convention_match(data, candidates)
|
|
240
|
+
if match is not None:
|
|
241
|
+
kwargs[target] = match
|
|
242
|
+
|
|
243
|
+
# Detect children array
|
|
244
|
+
if depth is None or depth > 0:
|
|
245
|
+
children_key = _find_convention_match(data, CHILDREN_KEYS)
|
|
246
|
+
if children_key is not None:
|
|
247
|
+
found, children_data = resolve_path(data, children_key)
|
|
248
|
+
if found and isinstance(children_data, list) and children_data:
|
|
249
|
+
child_kwargs: Dict[str, Any] = {"path": children_key}
|
|
250
|
+
sample = children_data[0]
|
|
251
|
+
if isinstance(sample, dict):
|
|
252
|
+
for target, candidates in CHILD_CONVENTIONS.items():
|
|
253
|
+
match = _find_convention_match(sample, candidates)
|
|
254
|
+
if match is not None:
|
|
255
|
+
child_kwargs[target] = match
|
|
256
|
+
kwargs["children"] = ChildMapping(**child_kwargs)
|
|
257
|
+
|
|
258
|
+
return TraceMapping(**kwargs)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
# =============================================================================
|
|
262
|
+
# Mapping Normalization
|
|
263
|
+
# =============================================================================
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def normalize_mapping(raw: dict) -> Tuple[TraceMapping, List[str]]:
|
|
267
|
+
"""Convert a flat dict-form mapping to a TraceMapping.
|
|
268
|
+
|
|
269
|
+
Accepts keys like "trace.name", "trace.input", "children", "children.name".
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
(mapping, unrecognized_keys) -- the mapping and any keys that weren't
|
|
273
|
+
recognized. Unrecognized keys likely indicate typos.
|
|
274
|
+
"""
|
|
275
|
+
trace_kwargs: Dict[str, Any] = {}
|
|
276
|
+
child_kwargs: Dict[str, Any] = {}
|
|
277
|
+
unrecognized: List[str] = []
|
|
278
|
+
|
|
279
|
+
for key, value in raw.items():
|
|
280
|
+
if key.startswith("trace."):
|
|
281
|
+
field = key[len("trace.") :]
|
|
282
|
+
trace_kwargs[field] = value
|
|
283
|
+
elif key == "children":
|
|
284
|
+
child_kwargs["path"] = value
|
|
285
|
+
elif key.startswith("children."):
|
|
286
|
+
field = key[len("children.") :]
|
|
287
|
+
child_kwargs[field] = value
|
|
288
|
+
else:
|
|
289
|
+
unrecognized.append(key)
|
|
290
|
+
|
|
291
|
+
if child_kwargs and "path" in child_kwargs:
|
|
292
|
+
trace_kwargs["children"] = ChildMapping(**child_kwargs)
|
|
293
|
+
|
|
294
|
+
return TraceMapping(**trace_kwargs), unrecognized
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
# =============================================================================
|
|
298
|
+
# Timestamp Coercion
|
|
299
|
+
# =============================================================================
|
|
300
|
+
|
|
301
|
+
_NANOS_PER_SECOND = 1_000_000_000
|
|
302
|
+
_NANOS_PER_MILLI = 1_000_000
|
|
303
|
+
_NANOS_PER_MICRO = 1_000
|
|
304
|
+
|
|
305
|
+
# Thresholds for distinguishing epoch units
|
|
306
|
+
_SECONDS_THRESHOLD = 10**12
|
|
307
|
+
_MILLIS_THRESHOLD = 10**15
|
|
308
|
+
_MICROS_THRESHOLD = 10**18
|
|
309
|
+
|
|
310
|
+
_UNIT_MULTIPLIERS = {
|
|
311
|
+
"s": _NANOS_PER_SECOND,
|
|
312
|
+
"ms": _NANOS_PER_MILLI,
|
|
313
|
+
"us": _NANOS_PER_MICRO,
|
|
314
|
+
"ns": 1,
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def coerce_timestamp(value: Any, unit: str = "auto") -> Optional[int]:
|
|
319
|
+
"""Convert a timestamp value to nanoseconds since epoch.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
value: The timestamp value to convert.
|
|
323
|
+
unit: Explicit unit for numeric values. One of "s", "ms", "us", "ns",
|
|
324
|
+
or "auto" (default). When "auto", the unit is inferred from
|
|
325
|
+
the magnitude of the value. Use an explicit unit to avoid
|
|
326
|
+
magnitude-based guessing.
|
|
327
|
+
|
|
328
|
+
Accepts:
|
|
329
|
+
- int/float: epoch seconds, milliseconds, microseconds, or nanoseconds
|
|
330
|
+
- str: ISO 8601 format
|
|
331
|
+
- datetime: Python datetime object
|
|
332
|
+
|
|
333
|
+
Returns None if the value cannot be coerced.
|
|
334
|
+
"""
|
|
335
|
+
if value is None:
|
|
336
|
+
return None
|
|
337
|
+
|
|
338
|
+
if isinstance(value, datetime):
|
|
339
|
+
if value.tzinfo is None:
|
|
340
|
+
value = value.replace(tzinfo=timezone.utc)
|
|
341
|
+
return int(value.timestamp() * _NANOS_PER_SECOND)
|
|
342
|
+
|
|
343
|
+
if isinstance(value, (int, float)):
|
|
344
|
+
if unit != "auto":
|
|
345
|
+
multiplier = _UNIT_MULTIPLIERS.get(unit)
|
|
346
|
+
if multiplier is None:
|
|
347
|
+
return None
|
|
348
|
+
return int(value * multiplier)
|
|
349
|
+
|
|
350
|
+
# Auto: infer unit from magnitude.
|
|
351
|
+
# Compare as int when possible to avoid float64 precision loss
|
|
352
|
+
# at the microsecond/nanosecond boundary (~1e18).
|
|
353
|
+
magnitude = value if isinstance(value, int) else float(value)
|
|
354
|
+
if magnitude < _SECONDS_THRESHOLD:
|
|
355
|
+
return int(value * _NANOS_PER_SECOND)
|
|
356
|
+
if magnitude < _MILLIS_THRESHOLD:
|
|
357
|
+
return int(value * _NANOS_PER_MILLI)
|
|
358
|
+
if magnitude < _MICROS_THRESHOLD:
|
|
359
|
+
return int(value * _NANOS_PER_MICRO)
|
|
360
|
+
return int(value)
|
|
361
|
+
|
|
362
|
+
if isinstance(value, str):
|
|
363
|
+
try:
|
|
364
|
+
dt = datetime.fromisoformat(value.replace("Z", "+00:00"))
|
|
365
|
+
if dt.tzinfo is None:
|
|
366
|
+
dt = dt.replace(tzinfo=timezone.utc)
|
|
367
|
+
return int(dt.timestamp() * _NANOS_PER_SECOND)
|
|
368
|
+
except (ValueError, TypeError):
|
|
369
|
+
return None
|
|
370
|
+
|
|
371
|
+
return None
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
# =============================================================================
|
|
375
|
+
# Field Merge
|
|
376
|
+
# =============================================================================
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def merge_fields(
|
|
380
|
+
mapped: Dict[str, Any],
|
|
381
|
+
explicit: Dict[str, Any],
|
|
382
|
+
context: Dict[str, Any],
|
|
383
|
+
defaults: Dict[str, Any],
|
|
384
|
+
) -> Dict[str, Any]:
|
|
385
|
+
"""Apply the merge strategy across priority levels.
|
|
386
|
+
|
|
387
|
+
Priority (highest to lowest):
|
|
388
|
+
1. explicit -- push() keyword arguments
|
|
389
|
+
2. mapped -- values extracted from JSON via mapping
|
|
390
|
+
3. context -- ambient tracing_context() / run context
|
|
391
|
+
4. defaults -- from tracing.init()
|
|
392
|
+
|
|
393
|
+
Special rules:
|
|
394
|
+
- tags: union, deduplicated
|
|
395
|
+
- metadata: deep merge, higher priority wins on key conflict
|
|
396
|
+
"""
|
|
397
|
+
result: Dict[str, Any] = {}
|
|
398
|
+
all_sources = [defaults, context, mapped, explicit]
|
|
399
|
+
|
|
400
|
+
# Scalar fields: highest priority wins
|
|
401
|
+
scalar_fields = [
|
|
402
|
+
"name",
|
|
403
|
+
"session_id",
|
|
404
|
+
"user_id",
|
|
405
|
+
"run_id",
|
|
406
|
+
"environment",
|
|
407
|
+
"input",
|
|
408
|
+
"output",
|
|
409
|
+
"timestamp",
|
|
410
|
+
]
|
|
411
|
+
for field in scalar_fields:
|
|
412
|
+
for source in reversed(all_sources):
|
|
413
|
+
if field in source and source[field] is not None:
|
|
414
|
+
result[field] = source[field]
|
|
415
|
+
break
|
|
416
|
+
|
|
417
|
+
# Tags: union across all sources, deduplicated
|
|
418
|
+
all_tags: List[str] = []
|
|
419
|
+
for source in all_sources:
|
|
420
|
+
tags = source.get("tags")
|
|
421
|
+
if isinstance(tags, list):
|
|
422
|
+
all_tags.extend(tags)
|
|
423
|
+
if all_tags:
|
|
424
|
+
result["tags"] = list(dict.fromkeys(all_tags)) # preserves order
|
|
425
|
+
|
|
426
|
+
# Metadata: deep merge, higher priority wins on conflict
|
|
427
|
+
merged_meta: Dict[str, Any] = {}
|
|
428
|
+
for source in all_sources:
|
|
429
|
+
meta = source.get("metadata")
|
|
430
|
+
if isinstance(meta, dict):
|
|
431
|
+
merged_meta.update(meta)
|
|
432
|
+
if merged_meta:
|
|
433
|
+
result["metadata"] = merged_meta
|
|
434
|
+
|
|
435
|
+
return result
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
# =============================================================================
|
|
439
|
+
# Mapping Validation
|
|
440
|
+
# =============================================================================
|
|
441
|
+
|
|
442
|
+
# Expected types for each mappable field
|
|
443
|
+
_EXPECTED_TYPES = {
|
|
444
|
+
"name": "str",
|
|
445
|
+
"input": "json_serializable",
|
|
446
|
+
"output": "json_serializable",
|
|
447
|
+
"metadata": "dict",
|
|
448
|
+
"tags": "list",
|
|
449
|
+
"session_id": "str",
|
|
450
|
+
"user_id": "str",
|
|
451
|
+
"run_id": "str",
|
|
452
|
+
"timestamp": "timestamp",
|
|
453
|
+
"environment": "str",
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
_CHILD_EXPECTED_TYPES = {
|
|
457
|
+
"name": "str",
|
|
458
|
+
"input": "json_serializable",
|
|
459
|
+
"output": "json_serializable",
|
|
460
|
+
"metadata": "dict",
|
|
461
|
+
"type": "str",
|
|
462
|
+
"model": "str",
|
|
463
|
+
"level": "str",
|
|
464
|
+
"start_time": "timestamp",
|
|
465
|
+
"end_time": "timestamp",
|
|
466
|
+
"usage": "dict",
|
|
467
|
+
"cost": "dict",
|
|
468
|
+
"model_parameters": "dict",
|
|
469
|
+
"status_message": "str",
|
|
470
|
+
"prompt_name": "str",
|
|
471
|
+
"prompt_version": "number",
|
|
472
|
+
"attributes": "dict",
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
_VALID_OBSERVATION_TYPES = {
|
|
476
|
+
"SPAN",
|
|
477
|
+
"GENERATION",
|
|
478
|
+
"TOOL",
|
|
479
|
+
"AGENT",
|
|
480
|
+
"CHAIN",
|
|
481
|
+
"RETRIEVER",
|
|
482
|
+
"EMBEDDING",
|
|
483
|
+
"EVALUATOR",
|
|
484
|
+
"GUARDRAIL",
|
|
485
|
+
"EVENT",
|
|
486
|
+
# Also accept lowercase
|
|
487
|
+
"span",
|
|
488
|
+
"generation",
|
|
489
|
+
"tool",
|
|
490
|
+
"agent",
|
|
491
|
+
"chain",
|
|
492
|
+
"retriever",
|
|
493
|
+
"embedding",
|
|
494
|
+
"evaluator",
|
|
495
|
+
"guardrail",
|
|
496
|
+
"event",
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
_VALID_LEVELS = {"DEBUG", "DEFAULT", "WARNING", "ERROR"}
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def _is_json_serializable(value: Any) -> bool:
|
|
503
|
+
"""Check if a value is JSON-serializable (str, dict, list, number, bool, None)."""
|
|
504
|
+
return isinstance(value, (str, int, float, bool, dict, list, type(None)))
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
def _check_type(value: Any, expected: str) -> bool:
|
|
508
|
+
"""Check if a value matches the expected type category."""
|
|
509
|
+
if expected == "str":
|
|
510
|
+
return isinstance(value, str)
|
|
511
|
+
if expected == "dict":
|
|
512
|
+
return isinstance(value, dict)
|
|
513
|
+
if expected == "list":
|
|
514
|
+
return isinstance(value, list)
|
|
515
|
+
if expected == "number":
|
|
516
|
+
return isinstance(value, (int, float))
|
|
517
|
+
if expected == "json_serializable":
|
|
518
|
+
return _is_json_serializable(value)
|
|
519
|
+
if expected == "timestamp":
|
|
520
|
+
return coerce_timestamp(value) is not None
|
|
521
|
+
return True
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
def validate_mapping(
|
|
525
|
+
data: dict,
|
|
526
|
+
mapping: TraceMapping,
|
|
527
|
+
) -> Tuple[List[ValidationIssue], List[ValidationIssue]]:
|
|
528
|
+
"""Validate that all mapping paths resolve and types match.
|
|
529
|
+
|
|
530
|
+
Returns (errors, warnings).
|
|
531
|
+
"""
|
|
532
|
+
errors: List[ValidationIssue] = []
|
|
533
|
+
warnings: List[ValidationIssue] = []
|
|
534
|
+
|
|
535
|
+
def _available_keys(d: dict) -> List[str]:
|
|
536
|
+
return list(d.keys())[:20]
|
|
537
|
+
|
|
538
|
+
# Validate trace-level fields
|
|
539
|
+
for field, expected in _EXPECTED_TYPES.items():
|
|
540
|
+
dot_path = getattr(mapping, field, None)
|
|
541
|
+
if dot_path is None:
|
|
542
|
+
continue
|
|
543
|
+
|
|
544
|
+
found, value = resolve_path(data, dot_path)
|
|
545
|
+
if not found:
|
|
546
|
+
issue = ValidationIssue(
|
|
547
|
+
field=f"trace.{field}",
|
|
548
|
+
path=dot_path,
|
|
549
|
+
issue="path_not_found",
|
|
550
|
+
message=f"Mapping path '{dot_path}' not found in data.",
|
|
551
|
+
available_keys=_available_keys(data),
|
|
552
|
+
)
|
|
553
|
+
if field in ("name", "input", "output"):
|
|
554
|
+
errors.append(issue)
|
|
555
|
+
else:
|
|
556
|
+
warnings.append(issue)
|
|
557
|
+
continue
|
|
558
|
+
|
|
559
|
+
if not _check_type(value, expected):
|
|
560
|
+
errors.append(
|
|
561
|
+
ValidationIssue(
|
|
562
|
+
field=f"trace.{field}",
|
|
563
|
+
path=dot_path,
|
|
564
|
+
issue="type_mismatch",
|
|
565
|
+
message=f"Field 'trace.{field}' resolved to type {type(value).__name__}, expected {expected}.",
|
|
566
|
+
expected_type=expected,
|
|
567
|
+
actual_type=type(value).__name__,
|
|
568
|
+
)
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
# Validate children
|
|
572
|
+
if mapping.children is not None:
|
|
573
|
+
_validate_children(data, mapping.children, errors, warnings)
|
|
574
|
+
|
|
575
|
+
return errors, warnings
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
def _validate_children(
|
|
579
|
+
data: dict,
|
|
580
|
+
child_mapping: ChildMapping,
|
|
581
|
+
errors: List[ValidationIssue],
|
|
582
|
+
warnings: List[ValidationIssue],
|
|
583
|
+
) -> None:
|
|
584
|
+
"""Validate children mapping paths against the data."""
|
|
585
|
+
found, children_data = resolve_path(data, child_mapping.path)
|
|
586
|
+
|
|
587
|
+
if not found:
|
|
588
|
+
errors.append(
|
|
589
|
+
ValidationIssue(
|
|
590
|
+
field="children",
|
|
591
|
+
path=child_mapping.path,
|
|
592
|
+
issue="path_not_found",
|
|
593
|
+
message=f"Children path '{child_mapping.path}' not found in data.",
|
|
594
|
+
available_keys=list(data.keys())[:20],
|
|
595
|
+
)
|
|
596
|
+
)
|
|
597
|
+
return
|
|
598
|
+
|
|
599
|
+
if not isinstance(children_data, list):
|
|
600
|
+
errors.append(
|
|
601
|
+
ValidationIssue(
|
|
602
|
+
field="children",
|
|
603
|
+
path=child_mapping.path,
|
|
604
|
+
issue="type_mismatch",
|
|
605
|
+
message=f"Children path '{child_mapping.path}' resolved to {type(children_data).__name__}, expected list.",
|
|
606
|
+
expected_type="list",
|
|
607
|
+
actual_type=type(children_data).__name__,
|
|
608
|
+
)
|
|
609
|
+
)
|
|
610
|
+
return
|
|
611
|
+
|
|
612
|
+
if not children_data:
|
|
613
|
+
return
|
|
614
|
+
|
|
615
|
+
# Validate against first child as sample
|
|
616
|
+
sample = children_data[0]
|
|
617
|
+
if not isinstance(sample, dict):
|
|
618
|
+
return
|
|
619
|
+
|
|
620
|
+
for field, expected in _CHILD_EXPECTED_TYPES.items():
|
|
621
|
+
dot_path = getattr(child_mapping, field, None)
|
|
622
|
+
if dot_path is None:
|
|
623
|
+
continue
|
|
624
|
+
|
|
625
|
+
found, value = resolve_path(sample, dot_path)
|
|
626
|
+
if not found:
|
|
627
|
+
warnings.append(
|
|
628
|
+
ValidationIssue(
|
|
629
|
+
field=f"children.{field}",
|
|
630
|
+
path=dot_path,
|
|
631
|
+
issue="path_not_found",
|
|
632
|
+
message=f"Mapping path '{dot_path}' not found in children[0].",
|
|
633
|
+
available_keys=list(sample.keys())[:20],
|
|
634
|
+
)
|
|
635
|
+
)
|
|
636
|
+
continue
|
|
637
|
+
|
|
638
|
+
if not _check_type(value, expected):
|
|
639
|
+
warnings.append(
|
|
640
|
+
ValidationIssue(
|
|
641
|
+
field=f"children.{field}",
|
|
642
|
+
path=dot_path,
|
|
643
|
+
issue="type_mismatch",
|
|
644
|
+
message=f"Field 'children.{field}' resolved to type {type(value).__name__}, expected {expected}.",
|
|
645
|
+
expected_type=expected,
|
|
646
|
+
actual_type=type(value).__name__,
|
|
647
|
+
)
|
|
648
|
+
)
|
|
649
|
+
|
|
650
|
+
# Extra validation for constrained string fields
|
|
651
|
+
if field == "type" and isinstance(value, str) and value not in _VALID_OBSERVATION_TYPES:
|
|
652
|
+
warnings.append(
|
|
653
|
+
ValidationIssue(
|
|
654
|
+
field="children.type",
|
|
655
|
+
path=dot_path,
|
|
656
|
+
issue="invalid_type_value",
|
|
657
|
+
message=f"Observation type '{value}' not recognized. Valid: SPAN, GENERATION, TOOL, AGENT, etc.",
|
|
658
|
+
)
|
|
659
|
+
)
|
|
660
|
+
|
|
661
|
+
if field == "level" and isinstance(value, str) and value.upper() not in _VALID_LEVELS:
|
|
662
|
+
warnings.append(
|
|
663
|
+
ValidationIssue(
|
|
664
|
+
field="children.level",
|
|
665
|
+
path=dot_path,
|
|
666
|
+
issue="invalid_type_value",
|
|
667
|
+
message=f"Level '{value}' not recognized. Valid: DEBUG, DEFAULT, WARNING, ERROR.",
|
|
668
|
+
)
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
# =============================================================================
|
|
673
|
+
# Inspection Helpers
|
|
674
|
+
# =============================================================================
|
|
675
|
+
|
|
676
|
+
# Heuristic suggestions for unmatched keys
|
|
677
|
+
_SUGGESTION_PATTERNS: List[Tuple[str, str, re.Pattern]] = [
|
|
678
|
+
("trace.output", "root", re.compile(r"(final|agent|llm).*(answer|output|result|response)", re.I)),
|
|
679
|
+
("trace.input", "root", re.compile(r"(user|agent|llm).*(input|query|question|prompt)", re.I)),
|
|
680
|
+
("children.input", "child", re.compile(r"(step|action|tool).*(input|query)", re.I)),
|
|
681
|
+
("children.output", "child", re.compile(r"(step|action|tool).*(output|result|response)", re.I)),
|
|
682
|
+
("children.model", "child", re.compile(r"(model|llm).*(used|name|id)", re.I)),
|
|
683
|
+
]
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
def suggest_mapping_for_key(key: str, level: str) -> Optional[str]:
|
|
687
|
+
"""Try to suggest a mapping target for an unrecognized key using heuristics."""
|
|
688
|
+
for target, target_level, pattern in _SUGGESTION_PATTERNS:
|
|
689
|
+
if target_level == level and pattern.search(key):
|
|
690
|
+
return target
|
|
691
|
+
|
|
692
|
+
# Simple suffix heuristics
|
|
693
|
+
lower = key.lower()
|
|
694
|
+
if level == "child":
|
|
695
|
+
if lower.endswith("_input") or lower.endswith("input"):
|
|
696
|
+
return "children.input"
|
|
697
|
+
if lower.endswith("_output") or lower.endswith("output"):
|
|
698
|
+
return "children.output"
|
|
699
|
+
if lower.endswith("_result") or lower.endswith("result"):
|
|
700
|
+
return "children.output"
|
|
701
|
+
|
|
702
|
+
return None
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
def describe_type(value: Any) -> str:
|
|
706
|
+
"""Return a human-readable type description for a value."""
|
|
707
|
+
if isinstance(value, list):
|
|
708
|
+
if value and isinstance(value[0], dict):
|
|
709
|
+
return "list[dict]"
|
|
710
|
+
if value and isinstance(value[0], str):
|
|
711
|
+
return "list[str]"
|
|
712
|
+
return "list"
|
|
713
|
+
return type(value).__name__
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
def truncate_sample(value: Any, max_len: int = 60) -> str:
|
|
717
|
+
"""Return a truncated string representation of a value."""
|
|
718
|
+
if isinstance(value, str):
|
|
719
|
+
if len(value) > max_len:
|
|
720
|
+
return json.dumps(value[:max_len] + "...")
|
|
721
|
+
return json.dumps(value)
|
|
722
|
+
if isinstance(value, dict):
|
|
723
|
+
s = json.dumps(value)
|
|
724
|
+
if len(s) > max_len:
|
|
725
|
+
return s[:max_len] + "..."
|
|
726
|
+
return s
|
|
727
|
+
if isinstance(value, list):
|
|
728
|
+
return f"({len(value)} items)"
|
|
729
|
+
return str(value)
|