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,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -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.