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
gatewaysdk/build.py
ADDED
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
"""Agent build identity — "the agent IS the manifest."
|
|
2
|
+
|
|
3
|
+
There is no build file and no lockfile. As the agent constructs itself, the
|
|
4
|
+
SDK observes everything that defines a build: tools registered through
|
|
5
|
+
:func:`define_tool` (name, declared version, effects, auto schema hash,
|
|
6
|
+
source location), prompts registered through :func:`register_prompt`, the
|
|
7
|
+
code ref from CI/env, and the SDK's own version. ``tracing.init(agent=...,
|
|
8
|
+
version=...)`` assembles the canonical manifest, computes the
|
|
9
|
+
content-addressed build hash, stamps ``gateway.build.hash`` on every span,
|
|
10
|
+
and auto-registers the build with Gateway (idempotent on hash — every
|
|
11
|
+
replica of the same code is one build). Releases are label moves on the
|
|
12
|
+
platform, never mutations here.
|
|
13
|
+
|
|
14
|
+
v1 versioning is developer-declared: you bump ``version`` on the agent and
|
|
15
|
+
on tools; Gateway records schema hashes as evidence alongside.
|
|
16
|
+
|
|
17
|
+
Mirrors ``@withgateway/sdk``'s ``src/build`` 1:1.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import functools
|
|
23
|
+
import hashlib
|
|
24
|
+
import inspect
|
|
25
|
+
import json
|
|
26
|
+
import logging
|
|
27
|
+
import os
|
|
28
|
+
import re
|
|
29
|
+
import threading
|
|
30
|
+
from typing import Any, Callable, Optional, TypeVar
|
|
31
|
+
|
|
32
|
+
logger = logging.getLogger("gatewaysdk.build")
|
|
33
|
+
|
|
34
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
35
|
+
|
|
36
|
+
_registered_tools: dict[str, dict[str, Any]] = {}
|
|
37
|
+
_registered_prompts: dict[str, str] = {}
|
|
38
|
+
_registered_skills: dict[str, str] = {}
|
|
39
|
+
_registered_artifacts: dict[str, dict[str, Any]] = {}
|
|
40
|
+
_active_build_hash: Optional[str] = None
|
|
41
|
+
|
|
42
|
+
# Late registration: agents often build tool maps AFTER init. Registered
|
|
43
|
+
# contexts get a debounced re-registration whenever the registry changes —
|
|
44
|
+
# content-addressed and idempotent; traces keep the init-time hash.
|
|
45
|
+
_active_contexts: list[dict[str, Any]] = []
|
|
46
|
+
_reregister_timer: Optional[threading.Timer] = None
|
|
47
|
+
_RE_REGISTER_DEBOUNCE_S = 3.0
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _notify_registry_changed() -> None:
|
|
51
|
+
global _reregister_timer
|
|
52
|
+
if not _active_contexts:
|
|
53
|
+
return
|
|
54
|
+
if _reregister_timer is not None:
|
|
55
|
+
_reregister_timer.cancel()
|
|
56
|
+
|
|
57
|
+
def _rerun() -> None:
|
|
58
|
+
global _reregister_timer
|
|
59
|
+
_reregister_timer = None
|
|
60
|
+
for context in list(_active_contexts):
|
|
61
|
+
manifest = assemble_manifest(context["agent_id"])
|
|
62
|
+
build_hash = compute_build_hash(manifest)
|
|
63
|
+
if build_hash == context.get("last_hash"):
|
|
64
|
+
continue
|
|
65
|
+
context["last_hash"] = build_hash
|
|
66
|
+
_post_build(context, manifest, build_hash)
|
|
67
|
+
|
|
68
|
+
_reregister_timer = threading.Timer(_RE_REGISTER_DEBOUNCE_S, _rerun)
|
|
69
|
+
_reregister_timer.daemon = True
|
|
70
|
+
_reregister_timer.start()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def canonical_json(value: Any) -> str:
|
|
74
|
+
"""Deterministic JSON: keys sorted recursively, arrays kept in order."""
|
|
75
|
+
# ensure_ascii=False matches JavaScript JSON.stringify (no \uXXXX escapes),
|
|
76
|
+
# so the SAME agent hashes identically from either SDK.
|
|
77
|
+
return json.dumps(
|
|
78
|
+
value, sort_keys=True, separators=(",", ":"), ensure_ascii=False, default=str
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _sha256(text: str) -> str:
|
|
83
|
+
return "sha256:" + hashlib.sha256(text.encode("utf-8")).hexdigest()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _capture_source() -> Optional[str]:
|
|
87
|
+
"""First app-code frame ("src/tools/checkout.py:42").
|
|
88
|
+
|
|
89
|
+
Skips only the SDK's OWN frames (this module, installed package) — not
|
|
90
|
+
every path containing "gatewaysdk", or apps developed inside a monorepo
|
|
91
|
+
next to the SDK would never resolve a source.
|
|
92
|
+
"""
|
|
93
|
+
for frame_info in inspect.stack()[1:]:
|
|
94
|
+
filename = frame_info.filename.replace("\\", "/")
|
|
95
|
+
if filename.endswith("gatewaysdk/build.py"):
|
|
96
|
+
continue
|
|
97
|
+
if "site-packages/gatewaysdk/" in filename:
|
|
98
|
+
continue
|
|
99
|
+
if filename.startswith("<"):
|
|
100
|
+
continue
|
|
101
|
+
parts = filename.split("/")
|
|
102
|
+
short = "/".join(parts[-4:]) if len(parts) > 4 else filename
|
|
103
|
+
return f"{short}:{frame_info.lineno}"
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# Ambient environment interception (gatewaysdk.environment, spec §4.4): the
|
|
108
|
+
# environment package installs ONE process-wide interceptor; the define_tool
|
|
109
|
+
# wrapper consults it per call. Returning the sentinel means "not intercepted —
|
|
110
|
+
# run the original function" (the identity path; also taken whenever no
|
|
111
|
+
# interceptor is installed or no world is active).
|
|
112
|
+
_TOOL_INTERCEPT_MISS = object()
|
|
113
|
+
_tool_call_interceptor: Optional[Callable[[str, Callable[..., Any], tuple, dict], Any]] = None
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def set_tool_call_interceptor(
|
|
117
|
+
interceptor: Optional[Callable[[str, Callable[..., Any], tuple, dict], Any]],
|
|
118
|
+
) -> None:
|
|
119
|
+
"""Install (or clear, with ``None``) the ambient tool-call interceptor.
|
|
120
|
+
|
|
121
|
+
Called by ``gatewaysdk.environment`` — not user-facing. The interceptor
|
|
122
|
+
receives ``(tool_name, original_fn, args, kwargs)`` and returns either the
|
|
123
|
+
call's result or :data:`_TOOL_INTERCEPT_MISS` to fall through.
|
|
124
|
+
"""
|
|
125
|
+
global _tool_call_interceptor
|
|
126
|
+
_tool_call_interceptor = interceptor
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def define_tool(
|
|
130
|
+
name: str,
|
|
131
|
+
*,
|
|
132
|
+
version: Optional[str] = None,
|
|
133
|
+
effects: Optional[str] = None, # "read" | "write" | "irreversible"
|
|
134
|
+
schema: Optional[Any] = None,
|
|
135
|
+
description: Optional[str] = None,
|
|
136
|
+
) -> Callable[[F], F]:
|
|
137
|
+
"""Register a tool's identity; usable as a decorator.
|
|
138
|
+
|
|
139
|
+
Example::
|
|
140
|
+
|
|
141
|
+
@define_tool("checkout", version="2.1", effects="write",
|
|
142
|
+
schema=CHECKOUT_SCHEMA, description="Complete a purchase")
|
|
143
|
+
def checkout(cart_id: str) -> str: ...
|
|
144
|
+
|
|
145
|
+
Or imperatively: ``define_tool("checkout", version="2.1", schema=...)(fn)``.
|
|
146
|
+
|
|
147
|
+
The returned callable behaves identically to ``fn`` (``functools.wraps``
|
|
148
|
+
preserves its attributes) — EXCEPT inside an active mock environment
|
|
149
|
+
(``with env:`` from ``gatewaysdk.environment``), where calls routed to the
|
|
150
|
+
env execute against the mock world instead of the original function. This
|
|
151
|
+
ambient seam is spec §4.4; outside an active world the wrapper is a
|
|
152
|
+
zero-behavior-change passthrough.
|
|
153
|
+
"""
|
|
154
|
+
source = _capture_source()
|
|
155
|
+
identity: dict[str, Any] = {
|
|
156
|
+
"name": name,
|
|
157
|
+
"schemaHash": _sha256(
|
|
158
|
+
canonical_json({"schema": schema, "description": description or ""})
|
|
159
|
+
),
|
|
160
|
+
}
|
|
161
|
+
if version is not None:
|
|
162
|
+
identity["version"] = version
|
|
163
|
+
if effects is not None:
|
|
164
|
+
identity["effects"] = effects
|
|
165
|
+
if description is not None:
|
|
166
|
+
identity["description"] = description[:500]
|
|
167
|
+
if source is not None:
|
|
168
|
+
identity["source"] = source
|
|
169
|
+
_registered_tools[name] = identity
|
|
170
|
+
_notify_registry_changed()
|
|
171
|
+
|
|
172
|
+
def _decorator(fn: F) -> F:
|
|
173
|
+
@functools.wraps(fn)
|
|
174
|
+
def _tool_wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
175
|
+
interceptor = _tool_call_interceptor
|
|
176
|
+
if interceptor is not None:
|
|
177
|
+
outcome = interceptor(name, fn, args, kwargs)
|
|
178
|
+
if outcome is not _TOOL_INTERCEPT_MISS:
|
|
179
|
+
return outcome
|
|
180
|
+
return fn(*args, **kwargs)
|
|
181
|
+
|
|
182
|
+
return _tool_wrapper # type: ignore[return-value]
|
|
183
|
+
|
|
184
|
+
return _decorator
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def register_prompt(
|
|
188
|
+
name: str, content: str, *, version: Optional[str] = None
|
|
189
|
+
) -> str:
|
|
190
|
+
"""Register a code-shipped prompt so it joins the build identity.
|
|
191
|
+
|
|
192
|
+
``SYSTEM = register_prompt("system", "You are…")`` — returns the content
|
|
193
|
+
unchanged. Platform-served prompts don't need this; pin them by label.
|
|
194
|
+
"""
|
|
195
|
+
_registered_prompts[name] = _sha256(content)
|
|
196
|
+
register_artifact("prompt", name, version=version, content=content)
|
|
197
|
+
return content
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def register_artifact(
|
|
201
|
+
kind: str,
|
|
202
|
+
name: str,
|
|
203
|
+
*,
|
|
204
|
+
version: Optional[str] = None,
|
|
205
|
+
content: Optional[str] = None,
|
|
206
|
+
ref: Optional[str] = None,
|
|
207
|
+
metadata: Optional[dict[str, str]] = None,
|
|
208
|
+
) -> dict[str, Any]:
|
|
209
|
+
"""Version ANY artifact the agent is built from — the generic primitive
|
|
210
|
+
behind register_prompt/register_skill. ``content`` hashes locally
|
|
211
|
+
(off-platform); ``ref`` pins a platform-hosted artifact
|
|
212
|
+
("prompt/system@label:production")."""
|
|
213
|
+
source = _capture_source()
|
|
214
|
+
identity: dict[str, Any] = {"kind": kind, "name": name}
|
|
215
|
+
if version is not None:
|
|
216
|
+
identity["version"] = version
|
|
217
|
+
if content is not None:
|
|
218
|
+
identity["contentHash"] = _sha256(content)
|
|
219
|
+
if ref is not None:
|
|
220
|
+
identity["ref"] = ref
|
|
221
|
+
if source is not None:
|
|
222
|
+
identity["source"] = source
|
|
223
|
+
if metadata:
|
|
224
|
+
identity["metadata"] = metadata
|
|
225
|
+
_registered_artifacts[f"{kind}:{name}"] = identity
|
|
226
|
+
_notify_registry_changed()
|
|
227
|
+
return identity
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def get_registered_artifacts() -> list[dict[str, Any]]:
|
|
231
|
+
return sorted(
|
|
232
|
+
_registered_artifacts.values(), key=lambda a: (a["kind"], a["name"])
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def register_skill(
|
|
237
|
+
name: str,
|
|
238
|
+
version: str,
|
|
239
|
+
*,
|
|
240
|
+
content: Optional[str] = None,
|
|
241
|
+
ref: Optional[str] = None,
|
|
242
|
+
) -> None:
|
|
243
|
+
"""Register a skill's identity — ``register_skill("triage", "1.0")`` —
|
|
244
|
+
so skills are versioned in the build like tools and prompts."""
|
|
245
|
+
_registered_skills[name] = version
|
|
246
|
+
register_artifact("skill", name, version=version, content=content, ref=ref)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def get_registered_skills() -> dict[str, str]:
|
|
250
|
+
return dict(sorted(_registered_skills.items()))
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def get_registered_tools() -> list[dict[str, Any]]:
|
|
254
|
+
return sorted(_registered_tools.values(), key=lambda t: t["name"])
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def get_registered_prompts() -> dict[str, str]:
|
|
258
|
+
return dict(sorted(_registered_prompts.items()))
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def reset_build_registry() -> None:
|
|
262
|
+
"""Test hook."""
|
|
263
|
+
global _active_build_hash, _reregister_timer
|
|
264
|
+
_registered_tools.clear()
|
|
265
|
+
_registered_prompts.clear()
|
|
266
|
+
_registered_skills.clear()
|
|
267
|
+
_registered_artifacts.clear()
|
|
268
|
+
_active_contexts.clear()
|
|
269
|
+
if _reregister_timer is not None:
|
|
270
|
+
_reregister_timer.cancel()
|
|
271
|
+
_reregister_timer = None
|
|
272
|
+
_active_build_hash = None
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _sdk_version() -> str:
|
|
276
|
+
try:
|
|
277
|
+
from importlib.metadata import version
|
|
278
|
+
|
|
279
|
+
return f"gatewaysdk=={version('gatewaysdk')}"
|
|
280
|
+
except Exception:
|
|
281
|
+
return "gatewaysdk"
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _paas_git_context() -> Optional[dict[str, Any]]:
|
|
285
|
+
"""Git context most PaaS runtimes inject automatically (Vercel, Render,
|
|
286
|
+
Railway, Netlify, Heroku). On those hosts attribution is fully
|
|
287
|
+
zero-config — no GATEWAY_* or GITHUB_* env plumbing needed. Explicit
|
|
288
|
+
env vars always win; this only fills gaps."""
|
|
289
|
+
if os.getenv("VERCEL_GIT_COMMIT_SHA"):
|
|
290
|
+
# Only surface the repo when it's GitHub-shaped — enrichment is
|
|
291
|
+
# GitHub-only; a GitLab/Bitbucket repo would just 404 over there.
|
|
292
|
+
is_github = (os.getenv("VERCEL_GIT_PROVIDER") or "github") == "github"
|
|
293
|
+
owner = os.getenv("VERCEL_GIT_REPO_OWNER")
|
|
294
|
+
slug = os.getenv("VERCEL_GIT_REPO_SLUG")
|
|
295
|
+
return {
|
|
296
|
+
"provider": "vercel",
|
|
297
|
+
"sha": os.getenv("VERCEL_GIT_COMMIT_SHA"),
|
|
298
|
+
"repo": f"{owner}/{slug}" if is_github and owner and slug else None,
|
|
299
|
+
"branch": os.getenv("VERCEL_GIT_COMMIT_REF"),
|
|
300
|
+
"login": os.getenv("VERCEL_GIT_COMMIT_AUTHOR_LOGIN"),
|
|
301
|
+
}
|
|
302
|
+
if os.getenv("RENDER_GIT_COMMIT"):
|
|
303
|
+
return {
|
|
304
|
+
"provider": "render",
|
|
305
|
+
"sha": os.getenv("RENDER_GIT_COMMIT"),
|
|
306
|
+
"repo": os.getenv("RENDER_GIT_REPO_SLUG"), # already "owner/repo"
|
|
307
|
+
"branch": os.getenv("RENDER_GIT_BRANCH"),
|
|
308
|
+
}
|
|
309
|
+
if os.getenv("RAILWAY_GIT_COMMIT_SHA"):
|
|
310
|
+
owner = os.getenv("RAILWAY_GIT_REPO_OWNER")
|
|
311
|
+
name = os.getenv("RAILWAY_GIT_REPO_NAME")
|
|
312
|
+
return {
|
|
313
|
+
"provider": "railway",
|
|
314
|
+
"sha": os.getenv("RAILWAY_GIT_COMMIT_SHA"),
|
|
315
|
+
"repo": f"{owner}/{name}" if owner and name else None,
|
|
316
|
+
"branch": os.getenv("RAILWAY_GIT_BRANCH"),
|
|
317
|
+
"login": os.getenv("RAILWAY_GIT_AUTHOR"),
|
|
318
|
+
}
|
|
319
|
+
if os.getenv("NETLIFY") and os.getenv("COMMIT_REF"):
|
|
320
|
+
repo_match = re.search(
|
|
321
|
+
r"github\.com[/:]([^/]+/[^/.]+)", os.getenv("REPOSITORY_URL") or ""
|
|
322
|
+
)
|
|
323
|
+
return {
|
|
324
|
+
"provider": "netlify",
|
|
325
|
+
"sha": os.getenv("COMMIT_REF"),
|
|
326
|
+
"repo": repo_match.group(1) if repo_match else None,
|
|
327
|
+
"branch": os.getenv("BRANCH"),
|
|
328
|
+
}
|
|
329
|
+
# Heroku (dyno metadata) and common bare conventions: sha only — the
|
|
330
|
+
# platform resolves the repo server-side via the GitHub connection.
|
|
331
|
+
heroku_sha = os.getenv("HEROKU_SLUG_COMMIT") or os.getenv("SOURCE_VERSION")
|
|
332
|
+
bare_sha = heroku_sha or os.getenv("GIT_COMMIT") or os.getenv("COMMIT_SHA")
|
|
333
|
+
if bare_sha:
|
|
334
|
+
return {"provider": "heroku" if heroku_sha else "generic", "sha": bare_sha}
|
|
335
|
+
return None
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def _code_ref() -> Optional[str]:
|
|
339
|
+
paas = _paas_git_context() or {}
|
|
340
|
+
sha = (
|
|
341
|
+
os.getenv("GATEWAY_COMMIT")
|
|
342
|
+
or os.getenv("GITHUB_SHA")
|
|
343
|
+
or os.getenv("CI_COMMIT_SHA") # GitLab
|
|
344
|
+
or os.getenv("CIRCLE_SHA1")
|
|
345
|
+
or paas.get("sha")
|
|
346
|
+
)
|
|
347
|
+
if not sha:
|
|
348
|
+
return None
|
|
349
|
+
repo = (
|
|
350
|
+
os.getenv("GITHUB_REPOSITORY")
|
|
351
|
+
or os.getenv("CI_PROJECT_PATH")
|
|
352
|
+
or paas.get("repo")
|
|
353
|
+
)
|
|
354
|
+
return f"git:{repo}@{sha}" if repo else f"git:{sha}"
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def assemble_manifest(agent_id: str) -> dict[str, Any]:
|
|
358
|
+
manifest: dict[str, Any] = {
|
|
359
|
+
"agentId": agent_id,
|
|
360
|
+
"sdk": _sdk_version(),
|
|
361
|
+
"tools": get_registered_tools(),
|
|
362
|
+
"prompts": get_registered_prompts(),
|
|
363
|
+
"skills": get_registered_skills(),
|
|
364
|
+
"artifacts": get_registered_artifacts(),
|
|
365
|
+
}
|
|
366
|
+
code_ref = _code_ref()
|
|
367
|
+
if code_ref:
|
|
368
|
+
manifest["codeRef"] = code_ref
|
|
369
|
+
return manifest
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def compute_build_hash(manifest: dict[str, Any]) -> str:
|
|
373
|
+
"""Content-addressed identity. Source locations are display metadata, not
|
|
374
|
+
identity — the same tool declared on a different line is the same tool."""
|
|
375
|
+
identity = dict(manifest)
|
|
376
|
+
identity["tools"] = [
|
|
377
|
+
{k: v for k, v in tool.items() if k != "source"}
|
|
378
|
+
for tool in manifest.get("tools", [])
|
|
379
|
+
]
|
|
380
|
+
identity["artifacts"] = [
|
|
381
|
+
{k: v for k, v in artifact.items() if k != "source"}
|
|
382
|
+
for artifact in manifest.get("artifacts", [])
|
|
383
|
+
]
|
|
384
|
+
return _sha256(canonical_json(identity))
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def get_active_build_hash() -> Optional[str]:
|
|
388
|
+
return _active_build_hash
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _attribution_from_env() -> dict[str, Any]:
|
|
392
|
+
attribution: dict[str, Any] = {"source": "runtime"}
|
|
393
|
+
if os.getenv("GITHUB_ACTIONS"):
|
|
394
|
+
attribution["source"] = "ci"
|
|
395
|
+
if os.getenv("GITHUB_ACTOR"):
|
|
396
|
+
attribution["githubLogin"] = os.getenv("GITHUB_ACTOR")
|
|
397
|
+
sha = os.getenv("GATEWAY_COMMIT") or os.getenv("GITHUB_SHA")
|
|
398
|
+
if sha:
|
|
399
|
+
attribution["commitSha"] = sha
|
|
400
|
+
if os.getenv("GITHUB_REPOSITORY"):
|
|
401
|
+
attribution["repo"] = os.getenv("GITHUB_REPOSITORY")
|
|
402
|
+
branch = os.getenv("GITHUB_HEAD_REF") or os.getenv("GITHUB_REF_NAME")
|
|
403
|
+
if branch:
|
|
404
|
+
attribution["branch"] = branch
|
|
405
|
+
# PaaS-injected git context (Vercel/Render/Railway/Netlify/Heroku) fills
|
|
406
|
+
# any gaps — zero-config attribution on those hosts. Explicit env wins.
|
|
407
|
+
paas = _paas_git_context()
|
|
408
|
+
if paas:
|
|
409
|
+
if attribution["source"] == "runtime":
|
|
410
|
+
attribution["source"] = f"paas:{paas['provider']}"
|
|
411
|
+
if not attribution.get("commitSha") and paas.get("sha"):
|
|
412
|
+
attribution["commitSha"] = paas["sha"]
|
|
413
|
+
if not attribution.get("repo") and paas.get("repo"):
|
|
414
|
+
attribution["repo"] = paas["repo"]
|
|
415
|
+
if not attribution.get("branch") and paas.get("branch"):
|
|
416
|
+
attribution["branch"] = paas["branch"]
|
|
417
|
+
if not attribution.get("githubLogin") and paas.get("login"):
|
|
418
|
+
attribution["githubLogin"] = paas["login"]
|
|
419
|
+
pr_match = re.search(r"refs/pull/(\d+)/", os.getenv("GITHUB_REF") or "")
|
|
420
|
+
if pr_match:
|
|
421
|
+
attribution["prNumber"] = int(pr_match.group(1))
|
|
422
|
+
# PR title/body are NOT in the default Actions env — workflows pass them
|
|
423
|
+
# through: GATEWAY_PR_TITLE/GATEWAY_PR_BODY from github.event.pull_request.
|
|
424
|
+
if os.getenv("GATEWAY_PR_TITLE"):
|
|
425
|
+
attribution["prTitle"] = (os.getenv("GATEWAY_PR_TITLE") or "")[:300]
|
|
426
|
+
if os.getenv("GATEWAY_PR_BODY"):
|
|
427
|
+
attribution["prDescription"] = (os.getenv("GATEWAY_PR_BODY") or "")[:2000]
|
|
428
|
+
if attribution.get("repo") and attribution.get("prNumber") and "prUrl" not in attribution:
|
|
429
|
+
attribution["prUrl"] = (
|
|
430
|
+
f"https://github.com/{attribution['repo']}/pull/{attribution['prNumber']}"
|
|
431
|
+
)
|
|
432
|
+
return attribution
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def activate_build(
|
|
436
|
+
agent_id: str,
|
|
437
|
+
*,
|
|
438
|
+
version: Optional[str] = None,
|
|
439
|
+
host: Optional[str] = None,
|
|
440
|
+
public_key: Optional[str] = None,
|
|
441
|
+
secret_key: Optional[str] = None,
|
|
442
|
+
register: bool = True,
|
|
443
|
+
) -> str:
|
|
444
|
+
"""Assemble + hash the manifest, mark it active (spans stamp it), and
|
|
445
|
+
fire-and-forget registration with Gateway. Returns the build hash."""
|
|
446
|
+
global _active_build_hash
|
|
447
|
+
manifest = assemble_manifest(agent_id)
|
|
448
|
+
build_hash = compute_build_hash(manifest)
|
|
449
|
+
_active_build_hash = build_hash
|
|
450
|
+
logger.debug(
|
|
451
|
+
"Agent build identity: %s @ %s (%d tools, %d prompts)",
|
|
452
|
+
agent_id,
|
|
453
|
+
build_hash[:15],
|
|
454
|
+
len(manifest["tools"]),
|
|
455
|
+
len(manifest["prompts"]),
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
resolved_host = host or os.getenv("GATEWAY_HOST")
|
|
459
|
+
resolved_public = public_key or os.getenv("GATEWAY_PUBLIC_KEY")
|
|
460
|
+
resolved_secret = secret_key or os.getenv("GATEWAY_SECRET_KEY")
|
|
461
|
+
if not register or not (resolved_host and resolved_public and resolved_secret):
|
|
462
|
+
return build_hash
|
|
463
|
+
|
|
464
|
+
context = {
|
|
465
|
+
"host": resolved_host,
|
|
466
|
+
"public_key": resolved_public,
|
|
467
|
+
"secret_key": resolved_secret,
|
|
468
|
+
"agent_id": agent_id,
|
|
469
|
+
"version": version,
|
|
470
|
+
"last_hash": build_hash,
|
|
471
|
+
}
|
|
472
|
+
# Track so tools/prompts/skills registered AFTER init re-register the
|
|
473
|
+
# fullest manifest (debounced, content-addressed, idempotent).
|
|
474
|
+
_active_contexts.append(context)
|
|
475
|
+
_post_build(context, manifest, build_hash)
|
|
476
|
+
return build_hash
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def _post_build(
|
|
480
|
+
context: dict[str, Any], manifest: dict[str, Any], build_hash: str
|
|
481
|
+
) -> None:
|
|
482
|
+
"""Fire-and-forget POST of one build registration (daemon thread)."""
|
|
483
|
+
|
|
484
|
+
def _register() -> None:
|
|
485
|
+
import base64
|
|
486
|
+
from urllib import request as urllib_request
|
|
487
|
+
|
|
488
|
+
payload = {
|
|
489
|
+
"agentId": context["agent_id"],
|
|
490
|
+
"buildHash": build_hash,
|
|
491
|
+
"manifest": manifest,
|
|
492
|
+
"attribution": _attribution_from_env(),
|
|
493
|
+
}
|
|
494
|
+
if context.get("version"):
|
|
495
|
+
payload["semanticVer"] = context["version"]
|
|
496
|
+
try:
|
|
497
|
+
req = urllib_request.Request(
|
|
498
|
+
f"{str(context['host']).rstrip('/')}/api/public/agent-builds",
|
|
499
|
+
data=json.dumps(payload).encode("utf-8"),
|
|
500
|
+
headers={
|
|
501
|
+
"Authorization": "Basic "
|
|
502
|
+
+ base64.b64encode(
|
|
503
|
+
f"{context['public_key']}:{context['secret_key']}".encode()
|
|
504
|
+
).decode(),
|
|
505
|
+
"Content-Type": "application/json",
|
|
506
|
+
},
|
|
507
|
+
method="POST",
|
|
508
|
+
)
|
|
509
|
+
with urllib_request.urlopen(req, timeout=15):
|
|
510
|
+
pass
|
|
511
|
+
logger.debug("Registered agent build %s", build_hash[:15])
|
|
512
|
+
except Exception as exc: # noqa: BLE001 — fail-soft by design
|
|
513
|
+
logger.debug("Build registration failed (agent keeps running): %s", exc)
|
|
514
|
+
|
|
515
|
+
threading.Thread(target=_register, name="gateway-build-register", daemon=True).start()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Copyright (c) Microsoft. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""GatewaySDK command line interface entry point."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import importlib
|
|
9
|
+
import sys
|
|
10
|
+
from typing import Dict, Iterable, Tuple
|
|
11
|
+
|
|
12
|
+
_SUBCOMMANDS: Dict[str, Tuple[str, str]] = {
|
|
13
|
+
"vllm": ("gatewaysdk.cli.vllm", "Run the vLLM CLI with GatewaySDK instrumentation."),
|
|
14
|
+
"store": ("gatewaysdk.cli.store", "Run a LightningStore server."),
|
|
15
|
+
"prometheus": ("gatewaysdk.cli.prometheus", "Serve Prometheus metrics from the multiprocess registry."),
|
|
16
|
+
# "agentops" was removed: it dispatched to gatewaysdk.cli.agentops_server,
|
|
17
|
+
# a module that never existed, so the subcommand always crashed with
|
|
18
|
+
# ModuleNotFoundError. tests/test_cli_dispatch.py guards against repeats.
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
_DESCRIPTION = "GatewaySDK CLI entry point.\n\nAvailable subcommands:\n" + "\n".join(
|
|
22
|
+
f" {name:<10}{desc}" for name, (_, desc) in _SUBCOMMANDS.items()
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def main(argv: Iterable[str] | None = None) -> int:
|
|
27
|
+
"""Dispatch to the requested GatewaySDK subcommand."""
|
|
28
|
+
parser = argparse.ArgumentParser(
|
|
29
|
+
prog="msk",
|
|
30
|
+
description=_DESCRIPTION,
|
|
31
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
32
|
+
)
|
|
33
|
+
parser.add_argument("subcommand", choices=_SUBCOMMANDS.keys(), help="Subcommand to run.")
|
|
34
|
+
parser.add_argument("args", nargs=argparse.REMAINDER, help=argparse.SUPPRESS)
|
|
35
|
+
|
|
36
|
+
parsed = parser.parse_args(list(argv) if argv is not None else None)
|
|
37
|
+
module_name, _ = _SUBCOMMANDS[parsed.subcommand]
|
|
38
|
+
module = importlib.import_module(module_name)
|
|
39
|
+
|
|
40
|
+
entry_point = getattr(module, "main", None)
|
|
41
|
+
if entry_point is None:
|
|
42
|
+
parser.error(f"Subcommand '{parsed.subcommand}' does not define a callable 'main'")
|
|
43
|
+
|
|
44
|
+
dispatch_args = parsed.args
|
|
45
|
+
original_argv = sys.argv
|
|
46
|
+
sys.argv = [f"{parser.prog} {parsed.subcommand}", *dispatch_args]
|
|
47
|
+
try:
|
|
48
|
+
result = entry_point(dispatch_args or None)
|
|
49
|
+
finally:
|
|
50
|
+
sys.argv = original_argv
|
|
51
|
+
|
|
52
|
+
if isinstance(result, int):
|
|
53
|
+
return result
|
|
54
|
+
return 0
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
if __name__ == "__main__":
|
|
58
|
+
raise SystemExit(main())
|