interloper-toolkit 0.43.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.
@@ -0,0 +1,172 @@
1
+ """Scheduling tools — jobs, runs, and backfills: read-only monitoring.
2
+
3
+ Mutating operations (toggling jobs, triggering runs and backfills) live with
4
+ the agent — this module is shared with surfaces that must stay read-only.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from uuid import UUID
10
+
11
+ from interloper_toolkit.context import ToolkitContext
12
+ from interloper_toolkit.models import (
13
+ BackfillList,
14
+ FailureList,
15
+ JobHealth,
16
+ JobHealthStats,
17
+ JobList,
18
+ RunDetail,
19
+ RunErrorEvent,
20
+ RunFailure,
21
+ RunList,
22
+ ToolError,
23
+ )
24
+
25
+ # --- Jobs ---
26
+
27
+
28
+ def list_jobs(ctx: ToolkitContext) -> JobList | ToolError:
29
+ """List all scheduled jobs in the organisation.
30
+
31
+ Returns each job with its name, cron expression, enabled status,
32
+ last_run_at, and next_run_at.
33
+ """
34
+ try:
35
+ jobs = ctx.store.list_components(ctx.org_id, kinds=["job"])
36
+ return JobList(count=len(jobs), jobs=jobs)
37
+ except Exception as e:
38
+ return ToolError(error=str(e))
39
+
40
+
41
+ def get_job_health(ctx: ToolkitContext, component_id: str) -> JobHealth | ToolError:
42
+ """Get health summary for a job: metadata, recent success/failure rate.
43
+
44
+ Args:
45
+ component_id: UUID of the job to inspect.
46
+
47
+ Returns job metadata plus success rate computed from the last 20 runs.
48
+ """
49
+ try:
50
+ jid = UUID(component_id)
51
+ job = ctx.store.get_component(jid, kind="job")
52
+ runs = ctx.store.list_runs(ctx.org_id, component_id=jid, limit=20)
53
+
54
+ total = len(runs)
55
+ success = sum(1 for r in runs if r.status == "success")
56
+ failed = sum(1 for r in runs if r.status == "failed")
57
+
58
+ # Compute average duration for completed runs
59
+ durations = []
60
+ for r in runs:
61
+ if r.started_at and r.completed_at:
62
+ delta = r.completed_at - r.started_at
63
+ durations.append(delta.total_seconds())
64
+ avg_duration_seconds = sum(durations) / len(durations) if durations else None
65
+
66
+ return JobHealth(
67
+ job=job,
68
+ health=JobHealthStats(
69
+ total_recent_runs=total,
70
+ success_count=success,
71
+ failed_count=failed,
72
+ success_rate=round(success / total, 2) if total > 0 else None,
73
+ avg_duration_seconds=round(avg_duration_seconds, 1) if avg_duration_seconds else None,
74
+ ),
75
+ )
76
+ except Exception as e:
77
+ return ToolError(error=str(e))
78
+
79
+
80
+ # --- Runs ---
81
+
82
+
83
+ def list_recent_runs(
84
+ ctx: ToolkitContext,
85
+ component_id: str | None = None,
86
+ status: str | None = None,
87
+ limit: int = 20,
88
+ ) -> RunList | ToolError:
89
+ """List recent runs with optional filters.
90
+
91
+ Args:
92
+ component_id: Filter by job UUID (optional).
93
+ status: Filter by status: 'queued', 'running', 'success', 'failed', 'canceled' (optional).
94
+ limit: Maximum number of runs to return (default 20).
95
+ """
96
+ try:
97
+ runs = ctx.store.list_runs(
98
+ ctx.org_id,
99
+ component_id=UUID(component_id) if component_id else None,
100
+ status=status,
101
+ limit=limit,
102
+ )
103
+ return RunList(count=len(runs), runs=runs)
104
+ except Exception as e:
105
+ return ToolError(error=str(e))
106
+
107
+
108
+ def get_run_detail(ctx: ToolkitContext, run_id: str) -> RunDetail | ToolError:
109
+ """Get full detail for a single run including events and per-asset execution status.
110
+
111
+ Args:
112
+ run_id: UUID of the run.
113
+
114
+ Returns the run metadata, event timeline, and per-asset execution summary.
115
+ """
116
+ try:
117
+ rid = UUID(run_id)
118
+ run = ctx.store.get_run(rid)
119
+ events = ctx.store.list_events(run_id=rid)
120
+ asset_execs = ctx.store.list_asset_executions(rid)
121
+
122
+ return RunDetail(run=run, events=events, asset_executions=asset_execs)
123
+ except Exception as e:
124
+ return ToolError(error=str(e))
125
+
126
+
127
+ def list_failures(ctx: ToolkitContext, limit: int = 20) -> FailureList | ToolError:
128
+ """List recent failed runs with their error events.
129
+
130
+ Args:
131
+ limit: Maximum number of failed runs to return (default 20).
132
+
133
+ Returns failed runs along with the error messages from their events.
134
+ """
135
+ try:
136
+ failed_runs = ctx.store.list_runs(ctx.org_id, status="failed", limit=limit)
137
+
138
+ results = []
139
+ for run in failed_runs:
140
+ run_id = run.id
141
+ events = ctx.store.list_events(run_id=run_id)
142
+ errors = [
143
+ RunErrorEvent(asset_key=e.asset_key, error=e.error, timestamp=e.timestamp)
144
+ for e in events
145
+ if e.error
146
+ ]
147
+ results.append(RunFailure(run=run, errors=errors))
148
+
149
+ return FailureList(count=len(results), failures=results)
150
+ except Exception as e:
151
+ return ToolError(error=str(e))
152
+
153
+
154
+ # --- Backfills ---
155
+
156
+
157
+ def list_backfills(ctx: ToolkitContext, active_only: bool = True) -> BackfillList | ToolError:
158
+ """List backfills, optionally filtered to active ones only.
159
+
160
+ Args:
161
+ active_only: If true, only return running/queued backfills (default true).
162
+
163
+ Returns backfills with their status, date range, and partition progress.
164
+ """
165
+ try:
166
+ if active_only:
167
+ backfills = ctx.store.list_active_backfills(ctx.org_id)
168
+ else:
169
+ backfills = ctx.store.list_backfills(ctx.org_id)
170
+ return BackfillList(count=len(backfills), backfills=backfills)
171
+ except Exception as e:
172
+ return ToolError(error=str(e))
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.3
2
+ Name: interloper-toolkit
3
+ Version: 0.43.0
4
+ Summary: Interloper shared read-only tool functions for AI surfaces (agent, MCP)
5
+ Author: Guillaume Onfroy
6
+ Author-email: Guillaume Onfroy <guillaume@digitlcloud.com>
7
+ Requires-Dist: interloper-core
8
+ Requires-Dist: interloper-db
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+
12
+ # interloper-toolkit
13
+
14
+ The read-only tool functions shared by interloper's AI surfaces — the ADK
15
+ chat agent (`interloper-agent`) and the MCP server (`interloper-mcp`).
16
+
17
+ Every function takes a frozen `ToolkitContext(store, catalog, org_id)` as its
18
+ first argument and returns `<SuccessModel> | ToolError` — typed pydantic
19
+ results (see `models.py`) discriminated by the literal `status` field, never
20
+ raising. The models are the tool contract: MCP derives per-tool output
21
+ schemas from them, row-projecting models act as an allowlist of what leaves
22
+ the platform, and full-row payloads embed the interloper-db models to keep
23
+ that coupling visible rather than duplicated. The docstrings are LLM-facing:
24
+ both consumers surface them verbatim as tool descriptions.
25
+
26
+ Modules:
27
+
28
+ - `catalog` — the component definitions the platform ships (list, detail,
29
+ asset schemas, field search, schema comparison)
30
+ - `collection` — the org's component instances (read-only listing; sensitive
31
+ kinds project identity/metadata only)
32
+ - `lineage` — dependency analysis, impact assessment, DAG traversal
33
+ - `scheduling` — jobs, runs, and backfills: read-only monitoring
34
+ - `analytics` — run statistics, partition coverage, data freshness
35
+
36
+ Mutating operations (trigger/toggle/create) deliberately live with the agent,
37
+ not here — this package is safe to expose on read-only surfaces.
38
+
39
+ Depends only on `interloper-core` and `interloper-db`; no LLM-framework
40
+ dependencies (no google-adk, no mcp).
@@ -0,0 +1,11 @@
1
+ interloper_toolkit/__init__.py,sha256=DMqH8CcEPWezTUTEhN4sQlMyBrBgj8kO0fg1GYlMU58,627
2
+ interloper_toolkit/analytics.py,sha256=QHzPmcp9i3iNS1bWXSU8rwCPsUs_hBVy0-H7ZkIdMlA,5178
3
+ interloper_toolkit/catalog.py,sha256=YwFEPMsY-7cehLIZjBT3GV9X1aZx3MFjQRkOYopPbXk,12084
4
+ interloper_toolkit/collection.py,sha256=akurHQcQ2gYPIRNR4QchpPiHxeOyO2lQI921YP_YnrM,2322
5
+ interloper_toolkit/context.py,sha256=Euc7r0dOzSr0zMhfHWLrw8iV1wJkdT9P84S-Ml7Yj5M,1583
6
+ interloper_toolkit/lineage.py,sha256=6ZkKlmzon9CTn3IM9do6qu3Sq6--RqcclObD3FTtcPI,8235
7
+ interloper_toolkit/models.py,sha256=IVKTu8EKZrk6w0RApO1U6yM5X6rNT0hi37S1iULcncU,9956
8
+ interloper_toolkit/scheduling.py,sha256=iSujke74Mj8SoeQn0qSonVY_RNvAAOmXS8mLMrAksbs,5440
9
+ interloper_toolkit-0.43.0.dist-info/WHEEL,sha256=s49dN1sxqzkgPplo4QuUaKomil-_cbDzeLK4-pZKD-A,81
10
+ interloper_toolkit-0.43.0.dist-info/METADATA,sha256=WhBZU3EN7cL7woYRI--yWAz5Bx2B7phDJtCGImsthAM,1830
11
+ interloper_toolkit-0.43.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.11.24
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any