ags-cli 0.1.0__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.
Files changed (156) hide show
  1. ags_cli-0.1.0.dist-info/METADATA +332 -0
  2. ags_cli-0.1.0.dist-info/RECORD +156 -0
  3. ags_cli-0.1.0.dist-info/WHEEL +5 -0
  4. ags_cli-0.1.0.dist-info/entry_points.txt +2 -0
  5. ags_cli-0.1.0.dist-info/top_level.txt +2 -0
  6. cli/__init__.py +0 -0
  7. cli/__main__.py +4 -0
  8. cli/client.py +145 -0
  9. cli/commands/__init__.py +0 -0
  10. cli/commands/adapter.py +33 -0
  11. cli/commands/artifact.py +21 -0
  12. cli/commands/ask.py +212 -0
  13. cli/commands/chat.py +649 -0
  14. cli/commands/diff.py +49 -0
  15. cli/commands/doctor.py +93 -0
  16. cli/commands/gui.py +45 -0
  17. cli/commands/init.py +20 -0
  18. cli/commands/mcp.py +50 -0
  19. cli/commands/memory.py +65 -0
  20. cli/commands/model.py +73 -0
  21. cli/commands/policy.py +52 -0
  22. cli/commands/project.py +122 -0
  23. cli/commands/quota.py +107 -0
  24. cli/commands/run.py +84 -0
  25. cli/commands/serve.py +171 -0
  26. cli/commands/service.py +236 -0
  27. cli/commands/session.py +219 -0
  28. cli/commands/stats.py +96 -0
  29. cli/commands/status.py +36 -0
  30. cli/commands/task.py +37 -0
  31. cli/commands/usage.py +86 -0
  32. cli/local.py +84 -0
  33. cli/main.py +149 -0
  34. harness/__init__.py +4 -0
  35. harness/adapters/__init__.py +26 -0
  36. harness/adapters/antigravity.py +301 -0
  37. harness/adapters/claude_code.py +522 -0
  38. harness/adapters/local_openai.py +534 -0
  39. harness/adapters/mock.py +112 -0
  40. harness/adapters/probe.py +65 -0
  41. harness/adapters/registry.py +56 -0
  42. harness/adapters/warm_pool.py +255 -0
  43. harness/api/__init__.py +0 -0
  44. harness/api/router.py +38 -0
  45. harness/api/v1/__init__.py +0 -0
  46. harness/api/v1/adapters.py +105 -0
  47. harness/api/v1/approvals.py +173 -0
  48. harness/api/v1/artifacts.py +44 -0
  49. harness/api/v1/attachments.py +48 -0
  50. harness/api/v1/doctor.py +22 -0
  51. harness/api/v1/health.py +37 -0
  52. harness/api/v1/mcp.py +131 -0
  53. harness/api/v1/memory.py +80 -0
  54. harness/api/v1/policies.py +49 -0
  55. harness/api/v1/project.py +302 -0
  56. harness/api/v1/runs.py +98 -0
  57. harness/api/v1/sessions.py +248 -0
  58. harness/api/v1/stream.py +110 -0
  59. harness/api/v1/tasks.py +30 -0
  60. harness/api/v1/usage.py +58 -0
  61. harness/bootstrap.py +216 -0
  62. harness/db.py +164 -0
  63. harness/deps.py +58 -0
  64. harness/eventbus/__init__.py +20 -0
  65. harness/eventbus/inprocess_bus.py +85 -0
  66. harness/main.py +144 -0
  67. harness/mcp/__init__.py +22 -0
  68. harness/mcp/client.py +139 -0
  69. harness/mcp/config_gen.py +77 -0
  70. harness/mcp/registry.py +156 -0
  71. harness/mcp/tools.py +81 -0
  72. harness/memory/__init__.py +13 -0
  73. harness/memory/context_budget.py +116 -0
  74. harness/memory/embed.py +217 -0
  75. harness/memory/extract.py +74 -0
  76. harness/memory/ingest.py +106 -0
  77. harness/memory/namespaces.py +57 -0
  78. harness/memory/ranking.py +31 -0
  79. harness/memory/redact.py +37 -0
  80. harness/memory/service.py +320 -0
  81. harness/memory/sqlite_vec_backend.py +266 -0
  82. harness/memory/summarize.py +68 -0
  83. harness/models/__init__.py +35 -0
  84. harness/models/adapter_health.py +27 -0
  85. harness/models/approval.py +37 -0
  86. harness/models/artifact.py +35 -0
  87. harness/models/audit_log.py +33 -0
  88. harness/models/comparison.py +33 -0
  89. harness/models/enums.py +146 -0
  90. harness/models/mcp_server_config.py +49 -0
  91. harness/models/memory.py +76 -0
  92. harness/models/policy.py +29 -0
  93. harness/models/provider_config.py +35 -0
  94. harness/models/run.py +46 -0
  95. harness/models/run_event.py +35 -0
  96. harness/models/session.py +50 -0
  97. harness/models/task.py +30 -0
  98. harness/models/types.py +63 -0
  99. harness/models/workspace.py +27 -0
  100. harness/observability/__init__.py +4 -0
  101. harness/observability/audit.py +88 -0
  102. harness/observability/logging.py +47 -0
  103. harness/observability/metrics.py +43 -0
  104. harness/observability/tracing.py +38 -0
  105. harness/orchestrator/__init__.py +19 -0
  106. harness/orchestrator/engine.py +821 -0
  107. harness/orchestrator/handoff.py +33 -0
  108. harness/orchestrator/lifecycle.py +69 -0
  109. harness/orchestrator/native_resume.py +93 -0
  110. harness/orchestrator/policies.py +101 -0
  111. harness/orchestrator/reconcile.py +39 -0
  112. harness/orchestrator/run_graph.py +62 -0
  113. harness/orchestrator/snapshot.py +49 -0
  114. harness/schemas/__init__.py +1 -0
  115. harness/schemas/adapter.py +26 -0
  116. harness/schemas/approval.py +25 -0
  117. harness/schemas/artifact.py +17 -0
  118. harness/schemas/common.py +20 -0
  119. harness/schemas/memory.py +50 -0
  120. harness/schemas/policy.py +39 -0
  121. harness/schemas/run.py +116 -0
  122. harness/schemas/session.py +93 -0
  123. harness/schemas/task.py +24 -0
  124. harness/security/__init__.py +5 -0
  125. harness/security/approval_policy.py +107 -0
  126. harness/security/auth.py +106 -0
  127. harness/security/permissions.py +59 -0
  128. harness/security/risk.py +59 -0
  129. harness/security/secrets.py +49 -0
  130. harness/services/__init__.py +1 -0
  131. harness/services/adapters_health.py +212 -0
  132. harness/services/approvals.py +84 -0
  133. harness/services/artifacts.py +78 -0
  134. harness/services/attachments.py +228 -0
  135. harness/services/comparison.py +345 -0
  136. harness/services/doctor.py +156 -0
  137. harness/services/files.py +287 -0
  138. harness/services/mcp_servers.py +179 -0
  139. harness/services/project_git.py +101 -0
  140. harness/services/retention.py +97 -0
  141. harness/services/runs.py +155 -0
  142. harness/services/runs_diff.py +201 -0
  143. harness/services/sessions.py +242 -0
  144. harness/services/ssh.py +300 -0
  145. harness/services/stats.py +132 -0
  146. harness/services/tasks.py +41 -0
  147. harness/services/workspaces.py +184 -0
  148. harness/services/worktrees.py +439 -0
  149. harness/settings.py +186 -0
  150. harness/skills/__init__.py +11 -0
  151. harness/skills/manager.py +141 -0
  152. harness/tools/__init__.py +1 -0
  153. harness/tools/fs_tools.py +295 -0
  154. harness/workers/__init__.py +0 -0
  155. harness/workers/dispatch.py +26 -0
  156. harness/workers/inprocess.py +135 -0
@@ -0,0 +1,35 @@
1
+ from __future__ import annotations
2
+
3
+ import uuid
4
+ from datetime import datetime
5
+
6
+ from sqlalchemy import BigInteger, DateTime, Enum, ForeignKey, UniqueConstraint, func
7
+ from sqlalchemy.orm import Mapped, mapped_column
8
+
9
+ from harness.db import Base
10
+ from harness.models.enums import RunEventType
11
+ from harness.models.types import GUID, json_col
12
+
13
+
14
+ class RunEvent(Base):
15
+ """Append-only event ledger — the source of truth for a run. Run/session rows
16
+ are projections rebuilt from these events where practical. ``(run_id, seq)`` is
17
+ unique and monotonic for deterministic replay and timeline rendering."""
18
+
19
+ __tablename__ = "run_events"
20
+ __table_args__ = (
21
+ UniqueConstraint("run_id", "seq", name="uq_run_events_run_id_seq"),
22
+ )
23
+
24
+ id: Mapped[uuid.UUID] = mapped_column(
25
+ GUID(), primary_key=True, default=uuid.uuid4
26
+ )
27
+ run_id: Mapped[uuid.UUID] = mapped_column(
28
+ GUID(), ForeignKey("runs.id", ondelete="CASCADE"), index=True
29
+ )
30
+ seq: Mapped[int] = mapped_column(BigInteger)
31
+ ts: Mapped[datetime] = mapped_column(
32
+ DateTime(timezone=True), server_default=func.now()
33
+ )
34
+ type: Mapped[RunEventType] = mapped_column(Enum(RunEventType, name="run_event_type"))
35
+ payload: Mapped[dict] = mapped_column(json_col(), default=dict)
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+
3
+ import uuid
4
+
5
+ from sqlalchemy import Enum, ForeignKey, Index, Text
6
+ from sqlalchemy.orm import Mapped, mapped_column
7
+
8
+ from harness.db import Base, TimestampMixin
9
+ from harness.models.enums import SessionStatus
10
+ from harness.models.types import GUID, json_col
11
+
12
+
13
+ class Session(Base, TimestampMixin):
14
+ """A canonical, provider-independent unit of context. Holds the objective,
15
+ constraints, rolling summary, and references to provider runs. Sessions can
16
+ branch (``parent_session_id``) and be resumed from the summary, not the raw
17
+ transcript."""
18
+
19
+ __tablename__ = "sessions"
20
+ __table_args__ = (
21
+ # Recent-session lookup per workspace.
22
+ Index("ix_sessions_workspace_updated", "workspace_id", "updated_at"),
23
+ )
24
+
25
+ id: Mapped[uuid.UUID] = mapped_column(
26
+ GUID(), primary_key=True, default=uuid.uuid4
27
+ )
28
+ workspace_id: Mapped[uuid.UUID] = mapped_column(
29
+ GUID(), ForeignKey("workspaces.id", ondelete="CASCADE"), index=True
30
+ )
31
+ task_id: Mapped[uuid.UUID | None] = mapped_column(
32
+ GUID(), ForeignKey("tasks.id", ondelete="SET NULL"), nullable=True
33
+ )
34
+ parent_session_id: Mapped[uuid.UUID | None] = mapped_column(
35
+ GUID(), ForeignKey("sessions.id", ondelete="SET NULL"), nullable=True
36
+ )
37
+ canonical_objective: Mapped[str] = mapped_column(Text)
38
+ constraints: Mapped[dict] = mapped_column(json_col(), default=dict)
39
+ # Per-session runtime settings overriding workspace defaults. Keys:
40
+ # write_mode (bool|None: None = inherit workspace), workspace_mode
41
+ # ("main"|"worktree"), worktree_path/branch/base, worktree_fallback_reason,
42
+ # merged_at, merge_commit. Writers must copy-then-reassign the dict so the
43
+ # JSON column is flagged dirty (same pattern as Workspace.settings).
44
+ settings: Mapped[dict] = mapped_column(json_col(), default=dict)
45
+ native_sessions: Mapped[dict] = mapped_column(json_col(), default=dict)
46
+ summary: Mapped[str] = mapped_column(Text, default="")
47
+ summary_snapshots: Mapped[list] = mapped_column(json_col(), default=list)
48
+ status: Mapped[SessionStatus] = mapped_column(
49
+ Enum(SessionStatus, name="session_status"), default=SessionStatus.open
50
+ )
harness/models/task.py ADDED
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+
3
+ import uuid
4
+
5
+ from sqlalchemy import Enum, ForeignKey, String, Text
6
+ from sqlalchemy.orm import Mapped, mapped_column
7
+
8
+ from harness.db import Base, TimestampMixin
9
+ from harness.models.enums import TaskStatus
10
+ from harness.models.types import GUID, json_col
11
+
12
+
13
+ class Task(Base, TimestampMixin):
14
+ """A unit of work the user wants done; may spawn one or many sessions/runs."""
15
+
16
+ __tablename__ = "tasks"
17
+
18
+ id: Mapped[uuid.UUID] = mapped_column(
19
+ GUID(), primary_key=True, default=uuid.uuid4
20
+ )
21
+ workspace_id: Mapped[uuid.UUID] = mapped_column(
22
+ GUID(), ForeignKey("workspaces.id", ondelete="CASCADE"), index=True
23
+ )
24
+ title: Mapped[str] = mapped_column(String(512))
25
+ objective: Mapped[str] = mapped_column(Text)
26
+ constraints: Mapped[dict] = mapped_column(json_col(), default=dict)
27
+ status: Mapped[TaskStatus] = mapped_column(
28
+ Enum(TaskStatus, name="task_status"), default=TaskStatus.created
29
+ )
30
+ created_by: Mapped[str] = mapped_column(String(128), default="cli")
@@ -0,0 +1,63 @@
1
+ """Portable column types.
2
+
3
+ The platform runs on SQLite (daemonless, single profile). These helpers wrap the
4
+ column types used across the ORM models so that intent (UUID, JSON object/array,
5
+ list of strings, list of UUIDs, embedding vector) reads clearly at the model
6
+ definition site, even though most of them now just delegate to a plain SQLAlchemy
7
+ type.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import uuid
13
+
14
+ from sqlalchemy import JSON, Uuid
15
+ from sqlalchemy.types import TypeDecorator, TypeEngine
16
+
17
+
18
+ def GUID() -> TypeEngine:
19
+ """UUID column, stored as ``CHAR(32)`` on SQLite.
20
+
21
+ ``Uuid`` returns/accepts ``uuid.UUID`` objects."""
22
+ return Uuid(as_uuid=True)
23
+
24
+
25
+ def json_col() -> TypeEngine:
26
+ """A JSON object/array column."""
27
+ return JSON()
28
+
29
+
30
+ def str_array() -> TypeEngine:
31
+ """A list of strings, stored as a JSON list."""
32
+ return JSON()
33
+
34
+
35
+ class _UUIDListJSON(TypeDecorator):
36
+ """Stores ``list[uuid.UUID]`` as a JSON array of strings.
37
+
38
+ Coerces to/from ``uuid.UUID`` so callers see UUID objects rather than raw
39
+ strings."""
40
+
41
+ impl = JSON
42
+ cache_ok = True
43
+
44
+ def process_bind_param(self, value, dialect): # noqa: ANN001
45
+ if value is None:
46
+ return None
47
+ return [str(v) for v in value]
48
+
49
+ def process_result_value(self, value, dialect): # noqa: ANN001
50
+ if value is None:
51
+ return None
52
+ return [v if isinstance(v, uuid.UUID) else uuid.UUID(v) for v in value]
53
+
54
+
55
+ def uuid_array() -> TypeEngine:
56
+ """A list of UUIDs, stored as a JSON list of strings."""
57
+ return _UUIDListJSON()
58
+
59
+
60
+ def embedding_col(dim: int) -> TypeEngine:
61
+ """An embedding vector, stored as a JSON list of floats. Similarity is computed
62
+ in Python (see ``memory/service.py``)."""
63
+ return JSON()
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ import uuid
4
+
5
+ from sqlalchemy import Enum, String
6
+ from sqlalchemy.orm import Mapped, mapped_column
7
+
8
+ from harness.db import Base, TimestampMixin
9
+ from harness.models.enums import TrustPolicy
10
+ from harness.models.types import GUID, json_col
11
+
12
+
13
+ class Workspace(Base, TimestampMixin):
14
+ """A memory partition and trust boundary (e.g. one repo/project)."""
15
+
16
+ __tablename__ = "workspaces"
17
+
18
+ id: Mapped[uuid.UUID] = mapped_column(
19
+ GUID(), primary_key=True, default=uuid.uuid4
20
+ )
21
+ slug: Mapped[str] = mapped_column(String(128), unique=True, index=True)
22
+ name: Mapped[str] = mapped_column(String(256))
23
+ trust_policy: Mapped[TrustPolicy] = mapped_column(
24
+ Enum(TrustPolicy, name="trust_policy"), default=TrustPolicy.restricted
25
+ )
26
+ default_routing_policy: Mapped[str] = mapped_column(String(128), default="single")
27
+ settings: Mapped[dict] = mapped_column(json_col(), default=dict)
@@ -0,0 +1,4 @@
1
+ from harness.observability.audit import verify_chain, write_audit
2
+ from harness.observability.logging import configure_logging, get_logger
3
+
4
+ __all__ = ["configure_logging", "get_logger", "verify_chain", "write_audit"]
@@ -0,0 +1,88 @@
1
+ """Immutable, hash-chained audit log writer.
2
+
3
+ Each record's ``hash = sha256(prev_hash || canonical_json(record))``. The chain
4
+ makes tampering or deletion detectable: re-computing the chain and comparing the
5
+ head hash verifies integrity. Application code only ever appends."""
6
+
7
+ from __future__ import annotations
8
+
9
+ import hashlib
10
+ import json
11
+ from typing import Any
12
+
13
+ from sqlalchemy import select
14
+ from sqlalchemy.ext.asyncio import AsyncSession
15
+
16
+ from harness.models.audit_log import AuditLog
17
+
18
+
19
+ def _canonical(payload: dict[str, Any]) -> str:
20
+ return json.dumps(payload, sort_keys=True, separators=(",", ":"), default=str)
21
+
22
+
23
+ def _compute_hash(prev_hash: str | None, record: dict[str, Any]) -> str:
24
+ h = hashlib.sha256()
25
+ h.update((prev_hash or "").encode())
26
+ h.update(_canonical(record).encode())
27
+ return h.hexdigest()
28
+
29
+
30
+ async def write_audit(
31
+ session: AsyncSession,
32
+ *,
33
+ actor: str,
34
+ action: str,
35
+ target_type: str,
36
+ target_id: str | None = None,
37
+ before: dict | None = None,
38
+ after: dict | None = None,
39
+ ) -> AuditLog:
40
+ """Append one tamper-evident audit row. Caller's transaction commits it."""
41
+ prev = (
42
+ await session.execute(
43
+ select(AuditLog).order_by(AuditLog.ts.desc()).limit(1)
44
+ )
45
+ ).scalar_one_or_none()
46
+ prev_hash = prev.hash if prev else None
47
+
48
+ record = {
49
+ "actor": actor,
50
+ "action": action,
51
+ "target_type": target_type,
52
+ "target_id": target_id,
53
+ "before": before,
54
+ "after": after,
55
+ }
56
+ row = AuditLog(
57
+ actor=actor,
58
+ action=action,
59
+ target_type=target_type,
60
+ target_id=target_id,
61
+ before=before,
62
+ after=after,
63
+ prev_hash=prev_hash,
64
+ hash=_compute_hash(prev_hash, record),
65
+ )
66
+ session.add(row)
67
+ return row
68
+
69
+
70
+ async def verify_chain(session: AsyncSession) -> bool:
71
+ """Recompute the whole chain; returns True iff every link is intact."""
72
+ rows = (
73
+ await session.execute(select(AuditLog).order_by(AuditLog.ts.asc()))
74
+ ).scalars().all()
75
+ prev_hash: str | None = None
76
+ for row in rows:
77
+ record = {
78
+ "actor": row.actor,
79
+ "action": row.action,
80
+ "target_type": row.target_type,
81
+ "target_id": row.target_id,
82
+ "before": row.before,
83
+ "after": row.after,
84
+ }
85
+ if row.prev_hash != prev_hash or row.hash != _compute_hash(prev_hash, record):
86
+ return False
87
+ prev_hash = row.hash
88
+ return True
@@ -0,0 +1,47 @@
1
+ """Structured JSON logging via structlog. One configuration entrypoint called at
2
+ app and worker startup."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import logging
7
+ import sys
8
+
9
+ import structlog
10
+
11
+ from harness.settings import get_settings
12
+
13
+ _configured = False
14
+
15
+
16
+ def configure_logging() -> None:
17
+ global _configured
18
+ if _configured:
19
+ return
20
+ settings = get_settings()
21
+ level = getattr(logging, settings.log_level.upper(), logging.INFO)
22
+
23
+ shared = [
24
+ structlog.contextvars.merge_contextvars,
25
+ structlog.processors.add_log_level,
26
+ structlog.processors.TimeStamper(fmt="iso"),
27
+ structlog.processors.StackInfoRenderer(),
28
+ structlog.processors.format_exc_info,
29
+ ]
30
+ renderer = (
31
+ structlog.processors.JSONRenderer()
32
+ if settings.log_json
33
+ else structlog.dev.ConsoleRenderer()
34
+ )
35
+ structlog.configure(
36
+ processors=[*shared, renderer],
37
+ wrapper_class=structlog.make_filtering_bound_logger(level),
38
+ logger_factory=structlog.PrintLoggerFactory(file=sys.stdout),
39
+ cache_logger_on_first_use=True,
40
+ )
41
+ logging.basicConfig(level=level, stream=sys.stdout, format="%(message)s")
42
+ _configured = True
43
+
44
+
45
+ def get_logger(name: str = "harness") -> structlog.stdlib.BoundLogger:
46
+ configure_logging()
47
+ return structlog.get_logger(name)
@@ -0,0 +1,43 @@
1
+ """Prometheus metrics. Exposed at ``GET /metrics`` (see api.v1.health)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from prometheus_client import Counter, Gauge, Histogram
6
+
7
+ ADAPTER_LATENCY = Histogram(
8
+ "harness_adapter_latency_seconds",
9
+ "End-to-end adapter run latency.",
10
+ ["adapter_kind", "provider"],
11
+ buckets=(0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30, 60, 120, 300),
12
+ )
13
+
14
+ RUN_TOTAL = Counter(
15
+ "harness_runs_total", "Runs by terminal status.", ["adapter_kind", "status"]
16
+ )
17
+
18
+ RUN_FAILURES = Counter(
19
+ "harness_run_failures_total", "Run failures by adapter and reason.",
20
+ ["adapter_kind", "reason"],
21
+ )
22
+
23
+ TOKENS_TOTAL = Counter(
24
+ "harness_tokens_total", "Token accounting.", ["adapter_kind", "direction"]
25
+ )
26
+
27
+ COST_USD_TOTAL = Counter(
28
+ "harness_cost_usd_total", "Estimated cost in USD where known.", ["adapter_kind"]
29
+ )
30
+
31
+ MEMORY_QUERIES = Counter("harness_memory_queries_total", "Memory retrieval queries.")
32
+ MEMORY_HITS = Counter(
33
+ "harness_memory_hits_total", "Retrievals that returned >=1 item above threshold."
34
+ )
35
+
36
+ ACTIVE_RUNS = Gauge("harness_active_runs", "Currently running/streaming runs.")
37
+
38
+
39
+ def memory_hit_rate() -> float:
40
+ """Convenience for the GUI/health endpoint."""
41
+ queries = MEMORY_QUERIES._value.get() # type: ignore[attr-defined]
42
+ hits = MEMORY_HITS._value.get() # type: ignore[attr-defined]
43
+ return (hits / queries) if queries else 0.0
@@ -0,0 +1,38 @@
1
+ """OpenTelemetry bootstrap. No-op unless ``HARNESS_OTEL_ENABLED=true`` so local
2
+ dev and CI stay dependency-light."""
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import Any
7
+
8
+ from harness.settings import get_settings
9
+
10
+ _tracer: Any = None
11
+
12
+
13
+ def setup_tracing(app: Any = None) -> None:
14
+ global _tracer
15
+ settings = get_settings()
16
+ if not settings.otel_enabled:
17
+ return
18
+ from opentelemetry import trace
19
+ from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
20
+ from opentelemetry.sdk.resources import Resource
21
+ from opentelemetry.sdk.trace import TracerProvider
22
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
23
+
24
+ provider = TracerProvider(resource=Resource.create({"service.name": "ags"}))
25
+ provider.add_span_processor(
26
+ BatchSpanProcessor(OTLPSpanExporter(endpoint=settings.otel_exporter_otlp_endpoint))
27
+ )
28
+ trace.set_tracer_provider(provider)
29
+ _tracer = trace.get_tracer("harness")
30
+
31
+ if app is not None:
32
+ from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
33
+
34
+ FastAPIInstrumentor.instrument_app(app)
35
+
36
+
37
+ def get_tracer() -> Any:
38
+ return _tracer
@@ -0,0 +1,19 @@
1
+ from harness.orchestrator.engine import (
2
+ NodeResult,
3
+ create_runs,
4
+ execute_node,
5
+ execute_session,
6
+ )
7
+ from harness.orchestrator.policies import CompiledPolicy, compile_policy, load_policy_specs
8
+ from harness.orchestrator.run_graph import RunGraph
9
+
10
+ __all__ = [
11
+ "CompiledPolicy",
12
+ "NodeResult",
13
+ "RunGraph",
14
+ "compile_policy",
15
+ "create_runs",
16
+ "execute_node",
17
+ "execute_session",
18
+ "load_policy_specs",
19
+ ]