jack-data-science-agent 4.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.
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
__version__ = "4.1.0"
|
|
2
|
+
|
|
3
|
+
from data_science_agent.sdk import (
|
|
4
|
+
Agent,
|
|
5
|
+
Analysis,
|
|
6
|
+
Artifact,
|
|
7
|
+
Benchmark,
|
|
8
|
+
BenchmarkResult,
|
|
9
|
+
Dataset,
|
|
10
|
+
Evidence,
|
|
11
|
+
Insight,
|
|
12
|
+
Report,
|
|
13
|
+
Reproduction,
|
|
14
|
+
ReproductionResult,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"Agent",
|
|
19
|
+
"Analysis",
|
|
20
|
+
"Artifact",
|
|
21
|
+
"Benchmark",
|
|
22
|
+
"BenchmarkResult",
|
|
23
|
+
"Dataset",
|
|
24
|
+
"Evidence",
|
|
25
|
+
"Insight",
|
|
26
|
+
"Report",
|
|
27
|
+
"Reproduction",
|
|
28
|
+
"ReproductionResult",
|
|
29
|
+
"__version__",
|
|
30
|
+
]
|
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
"""Data Science Agent — Public SDK (W2 Distribution Hardening).
|
|
2
|
+
|
|
3
|
+
Public surface (§14): ``Agent, Dataset, Analysis, Evidence, Artifact, Benchmark, Reproduction``
|
|
4
|
+
plus stable companions ``Insight, Report, BenchmarkResult, ReproductionResult``.
|
|
5
|
+
|
|
6
|
+
Stability (§15 / §18): see :data:`API_STABILITY`. Only ``data_science_agent.*`` is public;
|
|
7
|
+
``dsa_agent``, ``dsa_tools`` etc. are ``Internal`` — public code must not import ``_internal``.
|
|
8
|
+
|
|
9
|
+
Each Stable API below documents: Description / Parameters / Return Value / Errors / Example / Version (§16).
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
from dataclasses import dataclass, field
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class Dataset:
|
|
22
|
+
"""A dataset handle for SDK calls.
|
|
23
|
+
|
|
24
|
+
Description:
|
|
25
|
+
Lightweight handle pointing to a local dataset file. Stable since 4.0.0.
|
|
26
|
+
|
|
27
|
+
Parameters:
|
|
28
|
+
path: Filesystem path to CSV/Parquet dataset.
|
|
29
|
+
dataset_id: Optional logical id (defaults to file stem).
|
|
30
|
+
rows: Populated after profiling if available.
|
|
31
|
+
cols: Populated after profiling if available.
|
|
32
|
+
|
|
33
|
+
Return Value:
|
|
34
|
+
``Dataset`` instance.
|
|
35
|
+
|
|
36
|
+
Errors:
|
|
37
|
+
No I/O on construction; ``Agent.profile`` / ``Agent.analyze`` may raise
|
|
38
|
+
``FileNotFoundError`` or ``ValueError`` for unsupported format.
|
|
39
|
+
|
|
40
|
+
Example:
|
|
41
|
+
>>> from data_science_agent import Dataset
|
|
42
|
+
>>> ds = Dataset.from_path("benchmarks/v2/datasets/sales.csv")
|
|
43
|
+
>>> ds.dataset_id
|
|
44
|
+
'sales'
|
|
45
|
+
|
|
46
|
+
Version:
|
|
47
|
+
4.0.0 Stable
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
path: str
|
|
51
|
+
dataset_id: str | None = None
|
|
52
|
+
rows: int | None = None
|
|
53
|
+
cols: int | None = None
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
def from_path(cls, path: str | Path) -> Dataset:
|
|
57
|
+
"""Create a Dataset from a filesystem path.
|
|
58
|
+
|
|
59
|
+
Parameters:
|
|
60
|
+
path: Path to dataset file.
|
|
61
|
+
|
|
62
|
+
Return Value:
|
|
63
|
+
``Dataset`` with ``path`` and ``dataset_id`` set to stem.
|
|
64
|
+
|
|
65
|
+
Errors:
|
|
66
|
+
Never raises for missing file (deferred to ``Agent``).
|
|
67
|
+
|
|
68
|
+
Example:
|
|
69
|
+
>>> Dataset.from_path("sales.csv").path
|
|
70
|
+
'sales.csv'
|
|
71
|
+
|
|
72
|
+
Version:
|
|
73
|
+
4.0.0 Stable
|
|
74
|
+
"""
|
|
75
|
+
p = Path(path)
|
|
76
|
+
return cls(path=str(p), dataset_id=p.stem)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass
|
|
80
|
+
class Evidence:
|
|
81
|
+
"""Evidence grounding an insight (Insight → Evidence → ToolCall → Dataset).
|
|
82
|
+
|
|
83
|
+
Description:
|
|
84
|
+
Evidence record produced by a tool call. Stable since 4.0.0.
|
|
85
|
+
|
|
86
|
+
Parameters:
|
|
87
|
+
id: Evidence id (e.g. ``ev-...``).
|
|
88
|
+
claim: Natural-language claim backed by this evidence.
|
|
89
|
+
source_type: One of ``sql|python|statistical_test|model|visualization``.
|
|
90
|
+
source_id: ToolCall id or artifact id backing the claim.
|
|
91
|
+
result: Tool output dict (JSON-serializable).
|
|
92
|
+
confidence: 0.0–1.0.
|
|
93
|
+
validation_status: ``pending|validated|rejected``.
|
|
94
|
+
|
|
95
|
+
Return Value:
|
|
96
|
+
``Evidence`` dataclass.
|
|
97
|
+
|
|
98
|
+
Errors:
|
|
99
|
+
Construction never raises; validation happens in ``Analysis.validation``.
|
|
100
|
+
|
|
101
|
+
Example:
|
|
102
|
+
>>> from data_science_agent import Evidence
|
|
103
|
+
>>> e = Evidence(id="ev-1", claim="price~revenue r=0.9", source_type="python", source_id="tc-1")
|
|
104
|
+
>>> e.confidence
|
|
105
|
+
0.0
|
|
106
|
+
|
|
107
|
+
Version:
|
|
108
|
+
4.0.0 Stable
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
id: str
|
|
112
|
+
claim: str
|
|
113
|
+
source_type: str
|
|
114
|
+
source_id: str
|
|
115
|
+
result: dict[str, Any] = field(default_factory=dict)
|
|
116
|
+
confidence: float = 0.0
|
|
117
|
+
validation_status: str = "pending"
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@dataclass
|
|
121
|
+
class Artifact:
|
|
122
|
+
"""Artifact produced during analysis (chart, table, report, etc.).
|
|
123
|
+
|
|
124
|
+
Description:
|
|
125
|
+
Pointer to a file artifact under ``artifacts/reports/<run_id>/``. Stable.
|
|
126
|
+
|
|
127
|
+
Parameters:
|
|
128
|
+
id: Artifact id.
|
|
129
|
+
type: ``dataset|code|sql|table|chart|model|notebook|report|evidence``.
|
|
130
|
+
path: Relative or absolute path.
|
|
131
|
+
metadata: Free-form metadata (e.g. ``{rows: 500}``).
|
|
132
|
+
created_by: Creator (default ``agent``).
|
|
133
|
+
created_at: ISO-8601 timestamp or None.
|
|
134
|
+
|
|
135
|
+
Return Value:
|
|
136
|
+
``Artifact`` instance.
|
|
137
|
+
|
|
138
|
+
Errors:
|
|
139
|
+
None on construction.
|
|
140
|
+
|
|
141
|
+
Example:
|
|
142
|
+
>>> Artifact(id="a-1", type="chart", path="artifacts/reports/run-1/chart.png")
|
|
143
|
+
Artifact(...)
|
|
144
|
+
|
|
145
|
+
Version:
|
|
146
|
+
4.0.0 Stable
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
id: str
|
|
150
|
+
type: str
|
|
151
|
+
path: str
|
|
152
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
153
|
+
created_by: str = "agent"
|
|
154
|
+
created_at: str | None = None
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@dataclass
|
|
158
|
+
class Insight:
|
|
159
|
+
"""Insight derived from evidence.
|
|
160
|
+
|
|
161
|
+
Description:
|
|
162
|
+
High-level finding linked to one or more ``Evidence`` ids. Stable.
|
|
163
|
+
|
|
164
|
+
Parameters:
|
|
165
|
+
id: Insight id.
|
|
166
|
+
finding: Natural-language finding.
|
|
167
|
+
evidence_ids: List of backing evidence ids.
|
|
168
|
+
limitation: Optional limitation note.
|
|
169
|
+
magnitude: Optional magnitude (e.g. ``large``).
|
|
170
|
+
significance: Optional significance (e.g. ``p<0.01``).
|
|
171
|
+
|
|
172
|
+
Return Value:
|
|
173
|
+
``Insight`` instance.
|
|
174
|
+
|
|
175
|
+
Errors:
|
|
176
|
+
None.
|
|
177
|
+
|
|
178
|
+
Example:
|
|
179
|
+
>>> Insight(id="in-1", finding="Revenue correlates with price", evidence_ids=["ev-1"])
|
|
180
|
+
|
|
181
|
+
Version:
|
|
182
|
+
4.0.0 Stable
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
id: str
|
|
186
|
+
finding: str
|
|
187
|
+
evidence_ids: list[str] = field(default_factory=list)
|
|
188
|
+
limitation: str | None = None
|
|
189
|
+
magnitude: str | None = None
|
|
190
|
+
significance: str | None = None
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
@dataclass
|
|
194
|
+
class Analysis:
|
|
195
|
+
"""Result of ``Agent.analyze``.
|
|
196
|
+
|
|
197
|
+
Description:
|
|
198
|
+
Complete analysis result: status, report, evidence, insights, artifacts,
|
|
199
|
+
tool_calls, validation, error, and raw_state. Stable.
|
|
200
|
+
|
|
201
|
+
Parameters:
|
|
202
|
+
run_id: Unique run id (``run-...``).
|
|
203
|
+
status: ``COMPLETED|FAILED|...`` (mirrors ``AnalysisState.status``).
|
|
204
|
+
report_markdown: Report markdown if generated.
|
|
205
|
+
evidence: List of ``Evidence``.
|
|
206
|
+
insights: List of ``Insight``.
|
|
207
|
+
artifacts: List of ``Artifact``.
|
|
208
|
+
tool_calls: Raw tool call dicts (JSON-serializable).
|
|
209
|
+
validation: Validation result dicts.
|
|
210
|
+
error: Error message if failed else None.
|
|
211
|
+
raw_state: Original ``AnalysisState`` (Internal, may be None).
|
|
212
|
+
|
|
213
|
+
Return Value:
|
|
214
|
+
``Analysis`` aggregate.
|
|
215
|
+
|
|
216
|
+
Errors:
|
|
217
|
+
``Agent.analyze`` raises ``FileNotFoundError`` for missing dataset,
|
|
218
|
+
``ValueError`` for empty task.
|
|
219
|
+
|
|
220
|
+
Example:
|
|
221
|
+
>>> from data_science_agent import Agent
|
|
222
|
+
>>> r = Agent().analyze_sync("benchmarks/v2/datasets/sales.csv", "Analyze revenue")
|
|
223
|
+
>>> r.status
|
|
224
|
+
'COMPLETED'
|
|
225
|
+
|
|
226
|
+
Version:
|
|
227
|
+
4.0.0 Stable
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
run_id: str
|
|
231
|
+
status: str
|
|
232
|
+
report_markdown: str | None = None
|
|
233
|
+
evidence: list[Evidence] = field(default_factory=list)
|
|
234
|
+
insights: list[Insight] = field(default_factory=list)
|
|
235
|
+
artifacts: list[Artifact] = field(default_factory=list)
|
|
236
|
+
tool_calls: list[dict[str, Any]] = field(default_factory=list)
|
|
237
|
+
validation: list[dict[str, Any]] = field(default_factory=list)
|
|
238
|
+
error: str | None = None
|
|
239
|
+
raw_state: Any = None
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
API_STABILITY: dict[str, str] = {
|
|
243
|
+
"Agent": "Stable",
|
|
244
|
+
"Dataset": "Stable",
|
|
245
|
+
"Analysis": "Stable",
|
|
246
|
+
"Evidence": "Stable",
|
|
247
|
+
"Artifact": "Stable",
|
|
248
|
+
"Insight": "Stable",
|
|
249
|
+
"Report": "Stable",
|
|
250
|
+
"Benchmark": "Stable",
|
|
251
|
+
"Reproduction": "Stable",
|
|
252
|
+
"BenchmarkResult": "Stable",
|
|
253
|
+
"ReproductionResult": "Stable",
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class Agent:
|
|
258
|
+
"""Stable SDK facade (W2) over Core Engine (graph + evidence). [Stable]
|
|
259
|
+
|
|
260
|
+
Description:
|
|
261
|
+
Primary entrypoint for analyses. Wraps ``dsa_agent.graph.run_analysis``
|
|
262
|
+
(LangGraph Planner→Scientist→Critic→Report) and exposes async and sync
|
|
263
|
+
variants. Stable since 4.0.0; async behavior is cancellation-friendly.
|
|
264
|
+
|
|
265
|
+
Parameters:
|
|
266
|
+
None on construction; methods take dataset + task.
|
|
267
|
+
|
|
268
|
+
Return Value:
|
|
269
|
+
Constructed ``Agent`` with ``version == "4.0.0"``.
|
|
270
|
+
|
|
271
|
+
Errors:
|
|
272
|
+
Methods may raise ``FileNotFoundError`` (missing dataset),
|
|
273
|
+
``ValueError`` (empty task / unsupported format).
|
|
274
|
+
|
|
275
|
+
Example:
|
|
276
|
+
>>> from data_science_agent import Agent, Dataset
|
|
277
|
+
>>> agent = Agent()
|
|
278
|
+
>>> result = agent.analyze_sync(Dataset.from_path("sales.csv"), "Analyze revenue")
|
|
279
|
+
>>> result.evidence[0].claim # doctest: +SKIP
|
|
280
|
+
|
|
281
|
+
Version:
|
|
282
|
+
4.0.0 Stable
|
|
283
|
+
"""
|
|
284
|
+
|
|
285
|
+
def __init__(self) -> None:
|
|
286
|
+
self._version = "4.1.0"
|
|
287
|
+
|
|
288
|
+
async def analyze(
|
|
289
|
+
self,
|
|
290
|
+
dataset: str | Path | Dataset,
|
|
291
|
+
task: str,
|
|
292
|
+
*,
|
|
293
|
+
run_id: str | None = None,
|
|
294
|
+
) -> Analysis:
|
|
295
|
+
"""Run an analysis (async).
|
|
296
|
+
|
|
297
|
+
Description:
|
|
298
|
+
Execute the agent graph for a dataset + natural-language task.
|
|
299
|
+
Returns evidence-grounded ``Analysis`` (report + evidence + artifacts).
|
|
300
|
+
|
|
301
|
+
Parameters:
|
|
302
|
+
dataset: Path string / ``Path`` / ``Dataset`` handle.
|
|
303
|
+
task: Natural-language question (non-empty).
|
|
304
|
+
run_id: Optional explicit run id for reproducibility.
|
|
305
|
+
|
|
306
|
+
Return Value:
|
|
307
|
+
``Analysis`` with ``status`` (COMPLETED), ``report_markdown``,
|
|
308
|
+
``evidence``, ``insights``, ``artifacts``, ``tool_calls``.
|
|
309
|
+
|
|
310
|
+
Errors:
|
|
311
|
+
``FileNotFoundError`` if dataset missing; ``ValueError`` if task empty.
|
|
312
|
+
|
|
313
|
+
Example:
|
|
314
|
+
>>> import asyncio
|
|
315
|
+
>>> from data_science_agent import Agent
|
|
316
|
+
>>> asyncio.run(Agent().analyze("sales.csv", "Analyze revenue")) # doctest: +SKIP
|
|
317
|
+
|
|
318
|
+
Version:
|
|
319
|
+
4.0.0 Stable
|
|
320
|
+
"""
|
|
321
|
+
from dsa_agent.graph import run_analysis
|
|
322
|
+
|
|
323
|
+
if isinstance(dataset, Dataset):
|
|
324
|
+
ds_path = dataset.path
|
|
325
|
+
ds_id = dataset.dataset_id or Path(ds_path).stem if ds_path else dataset.dataset_id or "dataset"
|
|
326
|
+
else:
|
|
327
|
+
ds_path = str(dataset)
|
|
328
|
+
ds_id = Path(ds_path).stem if ds_path else "dataset"
|
|
329
|
+
|
|
330
|
+
state = await run_analysis(dataset_path=ds_path, dataset_id=ds_id, user_query=task, run_id=run_id)
|
|
331
|
+
return Analysis(
|
|
332
|
+
run_id=state.run_id,
|
|
333
|
+
status=state.status.value if hasattr(state.status, "value") else str(state.status),
|
|
334
|
+
report_markdown=state.report_markdown,
|
|
335
|
+
evidence=[Evidence(**e.model_dump()) for e in state.evidence] if state.evidence and hasattr(state.evidence[0], "model_dump") else [Evidence(**dict(e)) for e in state.evidence],
|
|
336
|
+
insights=[Insight(**i.model_dump()) for i in state.insights] if state.insights and hasattr(state.insights[0], "model_dump") else [Insight(**dict(i)) for i in state.insights],
|
|
337
|
+
artifacts=[Artifact(**a.model_dump()) for a in state.artifacts] if state.artifacts and hasattr(state.artifacts[0], "model_dump") else [Artifact(**dict(a)) for a in state.artifacts],
|
|
338
|
+
tool_calls=[c.model_dump(mode="json") if hasattr(c, "model_dump") else dict(c) for c in state.tool_calls],
|
|
339
|
+
validation=[v.model_dump(mode="json") if hasattr(v, "model_dump") else dict(v) for v in state.validation_results],
|
|
340
|
+
error=state.error,
|
|
341
|
+
raw_state=state,
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
def analyze_sync(
|
|
345
|
+
self,
|
|
346
|
+
dataset: str | Path | Dataset,
|
|
347
|
+
task: str,
|
|
348
|
+
*,
|
|
349
|
+
run_id: str | None = None,
|
|
350
|
+
) -> Analysis:
|
|
351
|
+
"""Run an analysis (sync wrapper).
|
|
352
|
+
|
|
353
|
+
Description:
|
|
354
|
+
Sync wrapper around :meth:`analyze` via ``asyncio.run``.
|
|
355
|
+
Suitable for scripts/CLI; in Jupyter with a running loop, use ``await analyze``.
|
|
356
|
+
|
|
357
|
+
Parameters:
|
|
358
|
+
Same as :meth:`analyze`.
|
|
359
|
+
|
|
360
|
+
Return Value:
|
|
361
|
+
``Analysis``.
|
|
362
|
+
|
|
363
|
+
Errors:
|
|
364
|
+
Same as :meth:`analyze`; may raise ``RuntimeError`` if called inside
|
|
365
|
+
a running event loop (use ``await analyze`` instead).
|
|
366
|
+
|
|
367
|
+
Example:
|
|
368
|
+
>>> from data_science_agent import Agent
|
|
369
|
+
>>> Agent().analyze_sync("sales.csv", "Analyze revenue") # doctest: +SKIP
|
|
370
|
+
|
|
371
|
+
Version:
|
|
372
|
+
4.0.0 Stable
|
|
373
|
+
"""
|
|
374
|
+
return asyncio.run(self.analyze(dataset, task, run_id=run_id))
|
|
375
|
+
|
|
376
|
+
def profile(self, dataset: str | Path | Dataset) -> dict[str, Any]:
|
|
377
|
+
"""Profile a dataset.
|
|
378
|
+
|
|
379
|
+
Description:
|
|
380
|
+
Load a dataset via ``dsa_datasets.loader`` and return row count
|
|
381
|
+
and columns (Polars-aware). Stable.
|
|
382
|
+
|
|
383
|
+
Parameters:
|
|
384
|
+
dataset: Path or ``Dataset`` handle.
|
|
385
|
+
|
|
386
|
+
Return Value:
|
|
387
|
+
``{"rows": int, "columns": list[str], "path": str}``.
|
|
388
|
+
|
|
389
|
+
Errors:
|
|
390
|
+
``FileNotFoundError`` if missing; ``ValueError`` for unsupported format.
|
|
391
|
+
|
|
392
|
+
Example:
|
|
393
|
+
>>> Agent().profile("benchmarks/v2/datasets/sales.csv") # doctest: +SKIP
|
|
394
|
+
{'rows': 500, ...}
|
|
395
|
+
|
|
396
|
+
Version:
|
|
397
|
+
4.0.0 Stable
|
|
398
|
+
"""
|
|
399
|
+
from dsa_datasets.loader import load_dataframe
|
|
400
|
+
from dsa_datasets.validate import detect_format
|
|
401
|
+
|
|
402
|
+
p = Path(dataset.path) if isinstance(dataset, Dataset) else Path(str(dataset))
|
|
403
|
+
fmt = detect_format(p.name)
|
|
404
|
+
df = load_dataframe(p, fmt)
|
|
405
|
+
return {"rows": df.height if hasattr(df, "height") else len(df), "columns": list(df.columns), "path": str(p)}
|
|
406
|
+
|
|
407
|
+
@property
|
|
408
|
+
def version(self) -> str:
|
|
409
|
+
"""SDK version (mirrors ``pyproject.toml``).
|
|
410
|
+
|
|
411
|
+
Return Value:
|
|
412
|
+
``"4.0.0"`` string.
|
|
413
|
+
|
|
414
|
+
Version:
|
|
415
|
+
4.0.0 Stable
|
|
416
|
+
"""
|
|
417
|
+
return self._version
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
@dataclass
|
|
421
|
+
class BenchmarkResult:
|
|
422
|
+
"""Result of ``Benchmark.run``.
|
|
423
|
+
|
|
424
|
+
Description:
|
|
425
|
+
Aggregate benchmark outcome over catalog tasks. Stable.
|
|
426
|
+
|
|
427
|
+
Parameters:
|
|
428
|
+
n_tasks: Number of tasks executed.
|
|
429
|
+
aggregate: Aggregate metrics (task_success_rate etc.).
|
|
430
|
+
results: Per-task result dicts.
|
|
431
|
+
|
|
432
|
+
Return Value:
|
|
433
|
+
``BenchmarkResult``.
|
|
434
|
+
|
|
435
|
+
Errors:
|
|
436
|
+
``Benchmark.run`` may raise ``FileNotFoundError`` for missing catalog.
|
|
437
|
+
|
|
438
|
+
Example:
|
|
439
|
+
>>> from data_science_agent import Benchmark
|
|
440
|
+
>>> r = Benchmark().run(limit=1) # doctest: +SKIP
|
|
441
|
+
>>> r.n_tasks
|
|
442
|
+
1
|
|
443
|
+
|
|
444
|
+
Version:
|
|
445
|
+
4.0.0 Stable
|
|
446
|
+
"""
|
|
447
|
+
|
|
448
|
+
n_tasks: int
|
|
449
|
+
aggregate: dict[str, Any] = field(default_factory=dict)
|
|
450
|
+
results: list[dict[str, Any]] = field(default_factory=list)
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
class Benchmark:
|
|
454
|
+
"""Benchmark facade (V4 §16) over evaluation framework.
|
|
455
|
+
|
|
456
|
+
Description:
|
|
457
|
+
Runs ``dsa_evaluation.runner.run_benchmark`` and returns typed result.
|
|
458
|
+
Stable since 4.0.0; catalog default is ``benchmarks/ds-agent-benchmark``.
|
|
459
|
+
|
|
460
|
+
Parameters:
|
|
461
|
+
None on construction.
|
|
462
|
+
|
|
463
|
+
Return Value:
|
|
464
|
+
Constructed ``Benchmark``.
|
|
465
|
+
|
|
466
|
+
Errors:
|
|
467
|
+
``run`` may raise ``FileNotFoundError`` if catalog/datasets missing.
|
|
468
|
+
|
|
469
|
+
Example:
|
|
470
|
+
>>> from data_science_agent import Benchmark
|
|
471
|
+
>>> Benchmark().run(limit=1) # doctest: +SKIP
|
|
472
|
+
|
|
473
|
+
Version:
|
|
474
|
+
4.0.0 Stable
|
|
475
|
+
"""
|
|
476
|
+
|
|
477
|
+
def run(
|
|
478
|
+
self,
|
|
479
|
+
catalog: str | Path = "benchmarks/ds-agent-benchmark/catalog.json",
|
|
480
|
+
datasets: str | Path = "benchmarks/ds-agent-benchmark/datasets",
|
|
481
|
+
out: str | Path = "benchmarks/ds-agent-benchmark/results",
|
|
482
|
+
limit: int | None = None,
|
|
483
|
+
) -> BenchmarkResult:
|
|
484
|
+
"""Run benchmark.
|
|
485
|
+
|
|
486
|
+
Description:
|
|
487
|
+
Execute benchmark catalog over dataset dir.
|
|
488
|
+
|
|
489
|
+
Parameters:
|
|
490
|
+
catalog: Path to ``catalog.json``.
|
|
491
|
+
datasets: Directory of datasets.
|
|
492
|
+
out: Output dir for ``results.json`` etc.
|
|
493
|
+
limit: Optional limit for smoke runs.
|
|
494
|
+
|
|
495
|
+
Return Value:
|
|
496
|
+
``BenchmarkResult`` with ``n_tasks`` and ``aggregate``.
|
|
497
|
+
|
|
498
|
+
Errors:
|
|
499
|
+
``FileNotFoundError`` for missing paths.
|
|
500
|
+
|
|
501
|
+
Example:
|
|
502
|
+
>>> Benchmark().run(limit=1) # doctest: +SKIP
|
|
503
|
+
|
|
504
|
+
Version:
|
|
505
|
+
4.0.0 Stable
|
|
506
|
+
"""
|
|
507
|
+
from dsa_evaluation.runner import run_benchmark
|
|
508
|
+
|
|
509
|
+
payload = run_benchmark(Path(catalog), Path(datasets), Path(out), limit=limit)
|
|
510
|
+
return BenchmarkResult(
|
|
511
|
+
n_tasks=payload.get("n_tasks", 0),
|
|
512
|
+
aggregate=payload.get("aggregate", {}),
|
|
513
|
+
results=payload.get("results", []),
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
@dataclass
|
|
518
|
+
class ReproductionResult:
|
|
519
|
+
"""Result of ``Reproduction.run``.
|
|
520
|
+
|
|
521
|
+
Description:
|
|
522
|
+
6-dim reproducibility score (overall/execution/trajectory/by_level). Stable.
|
|
523
|
+
|
|
524
|
+
Parameters:
|
|
525
|
+
overall: Overall score 0–1.
|
|
526
|
+
execution: Execution match rate.
|
|
527
|
+
trajectory: Trajectory match rate.
|
|
528
|
+
by_level: Scores by level L0–L5.
|
|
529
|
+
out_dir: Output directory.
|
|
530
|
+
|
|
531
|
+
Return Value:
|
|
532
|
+
``ReproductionResult``.
|
|
533
|
+
|
|
534
|
+
Errors:
|
|
535
|
+
``run`` may raise on missing catalog; fallback writes ``out_dir`` alone.
|
|
536
|
+
|
|
537
|
+
Example:
|
|
538
|
+
>>> ReproductionResult(overall=0.9)
|
|
539
|
+
ReproductionResult(overall=0.9, ...)
|
|
540
|
+
|
|
541
|
+
Version:
|
|
542
|
+
4.0.0 Stable
|
|
543
|
+
"""
|
|
544
|
+
|
|
545
|
+
overall: float = 0.0
|
|
546
|
+
execution: float = 0.0
|
|
547
|
+
trajectory: float = 0.0
|
|
548
|
+
by_level: dict[str, float] = field(default_factory=dict)
|
|
549
|
+
out_dir: str = ""
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
class Reproduction:
|
|
553
|
+
"""Reproduction facade (V4 §16) over reproducibility harness.
|
|
554
|
+
|
|
555
|
+
Description:
|
|
556
|
+
Runs fresh-twice reproduction harness and reads ``comparison.json``.
|
|
557
|
+
Stable since 4.0.0.
|
|
558
|
+
|
|
559
|
+
Parameters:
|
|
560
|
+
None on construction.
|
|
561
|
+
|
|
562
|
+
Return Value:
|
|
563
|
+
``Reproduction``.
|
|
564
|
+
|
|
565
|
+
Errors:
|
|
566
|
+
``run`` may raise ``FileNotFoundError``; returns partial ``ReproductionResult`` on failure.
|
|
567
|
+
|
|
568
|
+
Example:
|
|
569
|
+
>>> from data_science_agent import Reproduction
|
|
570
|
+
>>> Reproduction().run() # doctest: +SKIP
|
|
571
|
+
|
|
572
|
+
Version:
|
|
573
|
+
4.0.0 Stable
|
|
574
|
+
"""
|
|
575
|
+
|
|
576
|
+
def run(
|
|
577
|
+
self,
|
|
578
|
+
catalog: str | Path = "benchmarks/v2/catalog.json",
|
|
579
|
+
datasets: str | Path = "benchmarks/v2/datasets",
|
|
580
|
+
out: str | Path = "reproduction/v2",
|
|
581
|
+
) -> ReproductionResult:
|
|
582
|
+
"""Run reproduction harness.
|
|
583
|
+
|
|
584
|
+
Description:
|
|
585
|
+
Execute ``_reproduce_benchmark`` (or fallback ``run_benchmark``) and parse
|
|
586
|
+
``comparison.json`` for 6-dim scores.
|
|
587
|
+
|
|
588
|
+
Parameters:
|
|
589
|
+
catalog: Catalog json.
|
|
590
|
+
datasets: Datasets dir.
|
|
591
|
+
out: Output dir for ``manifest.json/comparison.json``.
|
|
592
|
+
|
|
593
|
+
Return Value:
|
|
594
|
+
``ReproductionResult``.
|
|
595
|
+
|
|
596
|
+
Errors:
|
|
597
|
+
Never raises for missing ``comparison.json`` (returns empty scores).
|
|
598
|
+
|
|
599
|
+
Example:
|
|
600
|
+
>>> Reproduction().run() # doctest: +SKIP
|
|
601
|
+
|
|
602
|
+
Version:
|
|
603
|
+
4.0.0 Stable
|
|
604
|
+
"""
|
|
605
|
+
from dsa_evaluation.cli import _reproduce_benchmark
|
|
606
|
+
|
|
607
|
+
# _reproduce_benchmark is internal; fallback to runner if missing
|
|
608
|
+
try:
|
|
609
|
+
_reproduce_benchmark(Path(catalog), Path(datasets), Path(out))
|
|
610
|
+
except Exception:
|
|
611
|
+
from dsa_evaluation.runner import run_benchmark as _rb
|
|
612
|
+
|
|
613
|
+
_rb(Path(catalog), Path(datasets), Path(out))
|
|
614
|
+
# Try to read comparison
|
|
615
|
+
try:
|
|
616
|
+
import json
|
|
617
|
+
|
|
618
|
+
comp = json.loads((Path(out) / "comparison.json").read_text(encoding="utf-8"))
|
|
619
|
+
rs = comp.get("reproduction_score", {})
|
|
620
|
+
return ReproductionResult(
|
|
621
|
+
overall=float(rs.get("overall", 0)),
|
|
622
|
+
execution=float(rs.get("execution", 0)),
|
|
623
|
+
trajectory=float(rs.get("trajectory", 0)),
|
|
624
|
+
by_level=rs.get("by_level", {}),
|
|
625
|
+
out_dir=str(out),
|
|
626
|
+
)
|
|
627
|
+
except Exception:
|
|
628
|
+
return ReproductionResult(out_dir=str(out))
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
@dataclass
|
|
632
|
+
class Report:
|
|
633
|
+
"""Report handle.
|
|
634
|
+
|
|
635
|
+
Description:
|
|
636
|
+
Pointer to a generated report (markdown + optional path). Stable.
|
|
637
|
+
|
|
638
|
+
Parameters:
|
|
639
|
+
run_id: Associated run id.
|
|
640
|
+
markdown: Markdown content if in-memory.
|
|
641
|
+
path: Filesystem path if persisted.
|
|
642
|
+
|
|
643
|
+
Return Value:
|
|
644
|
+
``Report``.
|
|
645
|
+
|
|
646
|
+
Errors:
|
|
647
|
+
None.
|
|
648
|
+
|
|
649
|
+
Example:
|
|
650
|
+
>>> Report(run_id="run-1", markdown="# Report")
|
|
651
|
+
|
|
652
|
+
Version:
|
|
653
|
+
4.0.0 Stable
|
|
654
|
+
"""
|
|
655
|
+
|
|
656
|
+
run_id: str
|
|
657
|
+
markdown: str | None = None
|
|
658
|
+
path: str | None = None
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: jack-data-science-agent
|
|
3
|
+
Version: 4.1.0
|
|
4
|
+
Summary: An Evidence-Grounded Autonomous Data Science System — from natural language to reproducible analysis
|
|
5
|
+
Project-URL: Homepage, https://github.com/Jackxiaozhiren/data-science-agent
|
|
6
|
+
Project-URL: Repository, https://github.com/Jackxiaozhiren/data-science-agent
|
|
7
|
+
Project-URL: Documentation, https://github.com/Jackxiaozhiren/data-science-agent/blob/main/docs/getting-started.md
|
|
8
|
+
Project-URL: Changelog, https://github.com/Jackxiaozhiren/data-science-agent/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Issues, https://github.com/Jackxiaozhiren/data-science-agent/issues
|
|
10
|
+
Author-email: Data Science Agent Contributors <jackxiaozhiren@users.noreply.github.com>
|
|
11
|
+
Maintainer-email: Data Science Agent Maintainers <jackxiaozhiren@users.noreply.github.com>
|
|
12
|
+
License: MIT
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: agent,benchmark,data-science,duckdb,evidence,llm,mcp,polars,reproducibility
|
|
15
|
+
Classifier: Development Status :: 4 - Beta
|
|
16
|
+
Classifier: Framework :: FastAPI
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: Intended Audience :: Science/Research
|
|
19
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
|
+
Requires-Python: >=3.12
|
|
26
|
+
Requires-Dist: aiosqlite>=0.20
|
|
27
|
+
Requires-Dist: dsa-agent
|
|
28
|
+
Requires-Dist: dsa-api
|
|
29
|
+
Requires-Dist: dsa-datasets
|
|
30
|
+
Requires-Dist: dsa-evaluation
|
|
31
|
+
Requires-Dist: dsa-evidence
|
|
32
|
+
Requires-Dist: dsa-execution
|
|
33
|
+
Requires-Dist: dsa-llm
|
|
34
|
+
Requires-Dist: dsa-mcp
|
|
35
|
+
Requires-Dist: dsa-ml
|
|
36
|
+
Requires-Dist: dsa-plugins
|
|
37
|
+
Requires-Dist: dsa-reports
|
|
38
|
+
Requires-Dist: dsa-statistics
|
|
39
|
+
Requires-Dist: dsa-tools
|
|
40
|
+
Requires-Dist: dsa-visualization
|
|
41
|
+
Requires-Dist: duckdb>=1.0
|
|
42
|
+
Requires-Dist: fastapi>=0.110
|
|
43
|
+
Requires-Dist: greenlet>=3.5.5
|
|
44
|
+
Requires-Dist: httpx>=0.27
|
|
45
|
+
Requires-Dist: langchain-core>=0.3
|
|
46
|
+
Requires-Dist: langgraph>=0.2
|
|
47
|
+
Requires-Dist: matplotlib>=3.8
|
|
48
|
+
Requires-Dist: numpy>=1.26
|
|
49
|
+
Requires-Dist: openpyxl>=3.1
|
|
50
|
+
Requires-Dist: polars>=1.0
|
|
51
|
+
Requires-Dist: pyarrow>=15.0
|
|
52
|
+
Requires-Dist: pydantic-settings>=2.4
|
|
53
|
+
Requires-Dist: pydantic>=2.7
|
|
54
|
+
Requires-Dist: python-multipart>=0.0.9
|
|
55
|
+
Requires-Dist: scikit-learn>=1.4
|
|
56
|
+
Requires-Dist: scipy>=1.12
|
|
57
|
+
Requires-Dist: sqlalchemy>=2.0
|
|
58
|
+
Requires-Dist: uvicorn[standard]>=0.29
|
|
59
|
+
Provides-Extra: dev-jupyter
|
|
60
|
+
Requires-Dist: dsa-jupyter; extra == 'dev-jupyter'
|
|
61
|
+
Requires-Dist: ipykernel>=6.0; extra == 'dev-jupyter'
|
|
62
|
+
Requires-Dist: ipython>=8.0; extra == 'dev-jupyter'
|
|
63
|
+
Requires-Dist: jupyterlab>=4.0; extra == 'dev-jupyter'
|
|
64
|
+
Requires-Dist: nest-asyncio>=1.5; extra == 'dev-jupyter'
|
|
65
|
+
Provides-Extra: jupyter
|
|
66
|
+
Requires-Dist: dsa-jupyter; extra == 'jupyter'
|
|
67
|
+
Requires-Dist: ipykernel>=6.0; extra == 'jupyter'
|
|
68
|
+
Requires-Dist: ipython>=8.0; extra == 'jupyter'
|
|
69
|
+
Requires-Dist: nest-asyncio>=1.5; extra == 'jupyter'
|
|
70
|
+
Provides-Extra: time-series
|
|
71
|
+
Requires-Dist: statsmodels>=0.14; extra == 'time-series'
|
|
72
|
+
Description-Content-Type: text/markdown
|
|
73
|
+
|
|
74
|
+
# Data Science Agent — v4.1.0
|
|
75
|
+
|
|
76
|
+
> **An Evidence-Grounded Autonomous Data Science System.**
|
|
77
|
+
> Turn natural-language questions into reproducible statistical analysis, machine learning experiments, visualizations, and research reports.
|
|
78
|
+
|
|
79
|
+
**What is it?** Autonomous data science agent with grounded evidence chains (Insight → Evidence → ToolCall → Dataset hash).
|
|
80
|
+
**Why does it exist?** Turn NL questions into verifiable analyses rather than free-text LLM summaries.
|
|
81
|
+
**Why is it different?** Evidence-grounded · Reproducible bundles (`reproduce.sh` + `analysis.ipynb`) · Formal evaluation (10 dims × 6 levels, statistical rigor S01–S10) · Local-first (no cloud required, `Cloud $0`) · MCP 2026-07-28 stateless.
|
|
82
|
+
**How do I run it?** `uv sync --dev` → `uv run dsa demo` (one-command, see Quick Start).
|
|
83
|
+
**How is it evaluated?** Benchmark v2: `30 datasets / 100 tasks / 11 categories, seed 42` via `dsa --catalog benchmarks/v2/catalog.json ...` — metrics: task success, statistical/tool/evidence, evaluator_v2.
|
|
84
|
+
**How is it reproducible?** `dsa reproduce` ↔ `reproduction/{manifest,environment,results,comparison,logs}` + `ReproductionScore` (6-dim, L0–L5) — see `docs/v3/`.
|
|
85
|
+
|
|
86
|
+
V2 adds: Evaluation Framework · Scientific Benchmark v2 (30/100/11) · Reliability & Reproducibility · Failure Taxonomy F01–F15 · Observability · MCP 2026-07-28 Stateless · Security Hardening · Research Package (RQs + ablation A–F). V3 adds: scientific audit (0.3.0, §13–17 versioned), independent reproduction, statistical upgrade (evaluator_v2), cross-model frontier, human evaluation (11/100, Kappa/Alpha), external validation (`dsa demo`). V4 adds: **Stable** — SDK (`from data_science_agent import Agent`), product CLI (`dsa doctor/init/analyze/profile/benchmark`), plugin architecture, MCP Tools (18 stateless `+analyze` §36, 12/12 PASS), MCP Resources (5 schemes §37), Jupyter (`%dsa` + rich) · **Experimental** — Time Series Plugin (`dsa-time-series 1.0.0` → Stable after W3), MCP App (`/mcp-app` Dataset→Question→Analysis→Evidence→Viz→Report §36, explicit handles §38), VS Code (`Dataset Explorer / Ask DSA`) — see `docs/v4_1/RELEASE_MATRIX.md` (§58) + `docs/v4_1/MCP_COMPATIBILITY.md` (§40).
|
|
87
|
+
|
|
88
|
+
**Quantitative claims (see §45):** Any number like `50/50 @1.0`, `100/100 @1.0`, `81% coverage`, `13 routes` must cite `Benchmark Version + Commit + Report` (e.g. `benchmarks/v2 0.3.0 + commit 1b6c3bf + docs/v3/V2_FINAL_BASELINE.md` or `benchmarks/baseline`). Avoid `State-of-the-art / Best / Enterprise-grade / Production-ready` without evidence.
|
|
89
|
+
|
|
90
|
+
## Documentation
|
|
91
|
+
|
|
92
|
+
Docs: [Getting Started](./docs/getting-started.md) · [Agent](./docs/agent.md) · [Tools](./docs/tools.md) · [Evidence](./docs/evidence.md) · [API](./docs/api.md) · [MCP](./docs/MCP_DESIGN.md) · [Frontend IA](./docs/FRONTEND_IA.md) · [Research](./docs/research.md) · [Changelog](./CHANGELOG.md) · [Roadmap](./ROADMAP.md) · [Citation](./CITATION.cff)
|
|
93
|
+
V2: [Baseline Report](./docs/v2/Baseline%20Report.md) · [Evaluation](./docs/v2/evaluation.md) · [MCP 2026-07-28](./docs/v2/MCP_2026_Audit.md) · [Security (W9)](./docs/v2/security.md) · [Benchmark v2](./benchmarks/v2/README.md) · Benchmark baseline: [benchmarks/baseline](./benchmarks/baseline/README.md)
|
|
94
|
+
V3: [V2 Baseline Freeze](./docs/v3/V2_FINAL_BASELINE.md) · [Benchmark Audit](./docs/v3/BENCHMARK_AUDIT.md) · [Reproduction](./docs/v3/REPRODUCTION.md) · [Statistical Eval](./docs/v3/STATISTICAL_EVALUATION.md) · [Reliability](./docs/v3/RELIABILITY.md) · [Cross-Model](./docs/v3/CROSS_MODEL.md) · [Human Eval](./docs/v3/HUMAN_EVALUATION_GUIDE.md) · [External Validation](./docs/v3/EXTERNAL_VALIDATION.md) — `human-eval/` samples + `demo/` one-command
|
|
95
|
+
MkDocs: `uv run mkdocs serve` / `uv run mkdocs build` (see [mkdocs.yml](./mkdocs.yml)) — Architecture Freeze at [ARCHITECTURE_FREEZE_V0.1.md](./ARCHITECTURE_FREEZE_V0.1.md)
|
|
96
|
+
|
|
97
|
+
## Stack
|
|
98
|
+
|
|
99
|
+
Next.js 15 + TypeScript + Tailwind + shadcn/ui · FastAPI + Pydantic v2 + SQLAlchemy · LangGraph · DuckDB + Polars + PyArrow · SQLite · LLM Abstraction (OpenAI/Anthropic/Google/OpenRouter/Ollama) · Scikit-learn + SciPy + Matplotlib
|
|
100
|
+
|
|
101
|
+
## Quick Start
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Python
|
|
105
|
+
uv sync --dev
|
|
106
|
+
uv run pytest -q # ~86+ tests
|
|
107
|
+
uv run ruff check .
|
|
108
|
+
uv run mypy packages apps/api --ignore-missing-imports # 81 source files clean
|
|
109
|
+
|
|
110
|
+
# API (port 8000) — local-first, no cloud required
|
|
111
|
+
uv run uvicorn dsa_api.main:app --reload --port 8000 --app-dir apps/api/src
|
|
112
|
+
|
|
113
|
+
# Web (port 3000)
|
|
114
|
+
cd apps/web && npm install --legacy-peer-deps && npm run dev
|
|
115
|
+
# Build — V2: 13 routes (/benchmarks /evaluations /runs /runs/[id] /runs/[id]/replay /failures /research /mcp)
|
|
116
|
+
npm run build --workspace=dsa-web # 13 routes green
|
|
117
|
+
|
|
118
|
+
# Benchmark v1 (20 datasets / 50 tasks) — frozen baseline: benchmarks/baseline — 50/50 @1.0
|
|
119
|
+
# Benchmark v2 (30 datasets / 100 tasks) — benchmarks/v2 (Evaluation Framework + Evidence Validation)
|
|
120
|
+
uv run dsa --help
|
|
121
|
+
uv run dsa --limit 3
|
|
122
|
+
uv run dsa --limit 50
|
|
123
|
+
uv run dsa --catalog benchmarks/v2/catalog.json --datasets benchmarks/v2/datasets --limit 50 --out /tmp/v2-bench
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Demo (One-Command Smoke)
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# Start API
|
|
130
|
+
uv run uvicorn dsa_api.main:app --host 127.0.0.1 --port 8000 --app-dir apps/api/src &
|
|
131
|
+
|
|
132
|
+
# Upload sales.csv (note: explicit MIME needed with curl)
|
|
133
|
+
curl -F "file=@examples/datasets/sales.csv;type=text/csv" http://127.0.0.1:8000/api/v1/datasets/
|
|
134
|
+
# -> {"id": "<dataset_id>", "rows": 500, "cols": 6, ...}
|
|
135
|
+
|
|
136
|
+
# Run analysis (numeric correlation + evidence)
|
|
137
|
+
curl -X POST http://127.0.0.1:8000/api/v1/analysis/ \
|
|
138
|
+
-H 'Content-Type: application/json' \
|
|
139
|
+
-d '{"dataset_id": "<dataset_id>", "user_query": "Analyze correlation between price and revenue"}'
|
|
140
|
+
# -> {"id": "run-...", "status": "COMPLETED", "state": {"evidence": [...], "report_markdown": "..."}}
|
|
141
|
+
|
|
142
|
+
# Check report and SSE trace
|
|
143
|
+
curl http://127.0.0.1:8000/api/v1/analysis/<run_id>/report?format=markdown
|
|
144
|
+
curl -H "Accept: text/event-stream" http://127.0.0.1:8000/api/v1/analysis/<run_id>/events
|
|
145
|
+
|
|
146
|
+
# Or via frontend: http://localhost:3000/datasets -> upload -> Analyze -> trace
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## API
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
POST /api/v1/datasets/ upload (multipart, 100MB, MIME sniff, traversal block)
|
|
153
|
+
GET /api/v1/datasets/{id} profile + metadata
|
|
154
|
+
POST /api/v1/analysis/ {dataset_id, user_query} -> run_id (Agent graph)
|
|
155
|
+
GET /api/v1/analysis/{id} AnalysisState (polling)
|
|
156
|
+
GET /api/v1/analysis/{id}/events SSE: agent/tool/validation/report/completed (JSON fallback via Accept)
|
|
157
|
+
GET /api/v1/analysis/{id}/progress progress_pct + counts
|
|
158
|
+
GET /api/v1/analysis/{id}/report ?format=json|markdown
|
|
159
|
+
GET /api/v1/analysis/{id}/artifacts artifacts + tool_calls + progress
|
|
160
|
+
GET /api/v1/analysis/{id}/evidence/{evidence_id} evidence → tool_call → insights → dataset trace
|
|
161
|
+
POST /api/v1/analysis/{id}/approve HUMAN_REVIEW approval (HITL)
|
|
162
|
+
GET /health GET /ready GET /version GET /
|
|
163
|
+
|
|
164
|
+
MCP (adapter over Tool Layer, stateless 2026-07-28):
|
|
165
|
+
GET /mcp/tools GET /mcp/resources POST /mcp/call POST /mcp (JSON-RPC: initialize/tools/list/tools/call/resources/list/resources/read)
|
|
166
|
+
Tools: 18 — profile_dataset, inspect_dataset, query_dataset, run_sql, run_python,
|
|
167
|
+
run_statistical_test, correlation_analysis, train_model, evaluate_model,
|
|
168
|
+
create_visualization, get_evidence, generate_report, save_artifact,
|
|
169
|
+
forecast, assumption_check, feature_importance, causal_check, analyze — see docs/MCP_DESIGN.md
|
|
170
|
+
Resources: 5 — dataset://, evidence://, report://, artifact://, analysis:// (§37, explicit handles §38)
|
|
171
|
+
App: /mcp-app/ — Dataset→Question→Analysis→Evidence→Viz→Report (§36) — see docs/v4_1/MCP_COMPATIBILITY.md
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Frontend
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
/ Dashboard (recent analyses)
|
|
178
|
+
/datasets Upload + list (drag-drop, 100MB guard)
|
|
179
|
+
/datasets/[id] Profile (schema, missing, duplicates, cardinality)
|
|
180
|
+
/analysis Workspace (select dataset + natural language task)
|
|
181
|
+
/analysis/[runId] Trace (plan/tool calls/evidence/insights/validation/artifacts/report + evidence graph)
|
|
182
|
+
/reports Reports index
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Evidence & Reproducibility
|
|
186
|
+
|
|
187
|
+
Every important claim traces to executable computation:
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
Insight → Evidence → ToolCall → Dataset (hash)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Artifacts under `artifacts/reports/<runId>/`: `report.md` (with `![chart]` embeds), `experiment.json`, `reproduce.sh`, `analysis.ipynb` (executable cells: profile + per-tool + `run_analysis`), `evidence_graph.json`.
|
|
194
|
+
`uv run mkdocs serve` / `build --strict` · health: `GET /health → {status, details:{db,duckdb,polars,llm:{active,status}}, version}` + `GET /ready`.
|
|
195
|
+
|
|
196
|
+
## Benchmark
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
benchmarks/ds-agent-benchmark/
|
|
200
|
+
datasets/ 20 synthetic CSVs (seed 42, 8,770 rows)
|
|
201
|
+
catalog.json 50 tasks (EDA 8 / SQL 7 / Statistics 8 / Regression 6 / Classification 6 / Time Series 5 / Visualization 5 / Data Quality 5)
|
|
202
|
+
results/ (generated via dsa benchmark)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
uv run dsa --limit 3 --out /tmp/bench
|
|
207
|
+
cat benchmarks/ds-agent-benchmark/catalog.json | jq '.tasks | length' # 50
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Metrics: Task Success Rate, Statistical Accuracy, SQL Accuracy, Code Execution Success, Evidence Coverage, Unsupported Claim Rate, Mean Latency, By-Category breakdown.
|
|
211
|
+
|
|
212
|
+
## Security Boundary
|
|
213
|
+
|
|
214
|
+
File (MIME sniff + archive bomb guard), SQL (read-only allowlist + row limit), Python (AST allowlist + _safe_import, introspection block), Prompt Injection (dataset UNTRUSTED DATA, detection), Output (unsupported causal claim rewrite), Resource limits (tool call budget), HITL approval.
|
|
215
|
+
|
|
216
|
+
## Project Structure
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
data-science-agent/ (monorepo)
|
|
220
|
+
apps/api FastAPI
|
|
221
|
+
apps/web Next.js 15
|
|
222
|
+
packages/agent, tools, execution, statistics, ml, visualization, evidence, reports, datasets, llm, mcp, evaluation
|
|
223
|
+
benchmarks/ds-agent-benchmark
|
|
224
|
+
tests/unit, integration, security
|
|
225
|
+
docs/
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Development Roadmap
|
|
229
|
+
|
|
230
|
+
Phase 0 Architecture Freeze ✓ Phase 1 Scaffold ✓ Phase 2 Data Layer ✓ Phase 3 Tool Layer ✓ Phase 4 Agent Graph ✓ Phase 5 Evidence ✓ Phase 6 API ✓ Phase 7 Frontend ✓ Phase 8 Security ✓ Phase 9 Benchmark ✓ Phase 10 MCP ✓ Phase 11 Docs ✓ — see `ROADMAP.md` for V3.0 W1–W12.
|
|
231
|
+
V2.0 Research Grade ✓ `v2.0.0` (Evaluation 10×6 · Benchmark v2 30/100/11 · Reliability L0–L5/F01–F15 · MCP 2026-07-28 · Security 23) — `docs/v3/V2_FINAL_BASELINE.md`.
|
|
232
|
+
V3.0 Release ✓ `v3.0.0` (12 workstreams, `docs/v3/V2_FINAL_BASELINE.md` + `research/V3_RESEARCH_REPORT.md`).
|
|
233
|
+
V4.0 Ecosystem ✓ `v4.0.0` (SDK + CLI + Plugins + MCP Apps + Jupyter/VS Code + Community).
|
|
234
|
+
|
|
235
|
+
## Testing
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
uv run pytest -q # 155 tests (unit + integration + security + evals)
|
|
239
|
+
uv run pytest --cov --cov-report=term-missing # 81% cov (4597 stmts)
|
|
240
|
+
uv run mypy packages apps/api --ignore-missing-imports # strict, 92 source files clean
|
|
241
|
+
uv run ruff check packages apps/api tests # scoped per-file ignores
|
|
242
|
+
uv run dsa --limit 50 # 50/50 @1.0 (benchmarks/ds-agent-benchmark, 8 cats)
|
|
243
|
+
uv run dsa --catalog benchmarks/v2/catalog.json --datasets benchmarks/v2/datasets --limit 100 # 100/100 @1.0 (11 cats)
|
|
244
|
+
uv run dsa demo # one-command: demo dataset → evidence → report (§40/47)
|
|
245
|
+
uv run dsa external-validation # install + demo metrics (§42)
|
|
246
|
+
docker compose config && npm --prefix apps/web run build # compose healthcheck + 13 routes
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Docker
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
docker compose up # api :8000, web :3000
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Contributing / Security
|
|
256
|
+
|
|
257
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) · [SECURITY.md](./SECURITY.md) · [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) · [LICENSE](./LICENSE) (MIT)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
data_science_agent/__init__.py,sha256=j4lit9XRkI7dGUpxNSIwM4BXQ5eYW3Y6RfKfLKmqi5c,456
|
|
2
|
+
data_science_agent/sdk.py,sha256=sPcWCbOobw3ysr1ySFax5fYavU5r32BcRXxio1pHIpY,19617
|
|
3
|
+
jack_data_science_agent-4.1.0.dist-info/METADATA,sha256=wFLeaDIgfeK7vz3tDuSbbHudDWyPm9QzPvbUI1JpeZU,14579
|
|
4
|
+
jack_data_science_agent-4.1.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
5
|
+
jack_data_science_agent-4.1.0.dist-info/licenses/LICENSE,sha256=gkgxTdPCq7g0o3xaYAJAeNtHdPbeg_Rv0unarH36GXA,1088
|
|
6
|
+
jack_data_science_agent-4.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Data Science Agent Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|