dataface 0.1.6.dev62__py3-none-any.whl → 0.1.6.dev76__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.
- dataface/agent_api/_paths.py +19 -25
- dataface/ai/llm.py +36 -5
- dataface/cli/commands/render.py +8 -2
- {dataface-0.1.6.dev62.dist-info → dataface-0.1.6.dev76.dist-info}/METADATA +1 -1
- {dataface-0.1.6.dev62.dist-info → dataface-0.1.6.dev76.dist-info}/RECORD +8 -8
- {dataface-0.1.6.dev62.dist-info → dataface-0.1.6.dev76.dist-info}/WHEEL +0 -0
- {dataface-0.1.6.dev62.dist-info → dataface-0.1.6.dev76.dist-info}/entry_points.txt +0 -0
- {dataface-0.1.6.dev62.dist-info → dataface-0.1.6.dev76.dist-info}/licenses/LICENSE +0 -0
dataface/agent_api/_paths.py
CHANGED
|
@@ -65,7 +65,7 @@ class FaceRenderContext:
|
|
|
65
65
|
"""
|
|
66
66
|
|
|
67
67
|
face_file: Path
|
|
68
|
-
scoped_path: Path
|
|
68
|
+
scoped_path: Path
|
|
69
69
|
scoped_base: Path
|
|
70
70
|
project_root: Path
|
|
71
71
|
output_dir: Path
|
|
@@ -74,37 +74,34 @@ class FaceRenderContext:
|
|
|
74
74
|
|
|
75
75
|
def build_face_render_context(
|
|
76
76
|
face_path: Path,
|
|
77
|
-
project_dir: Path
|
|
77
|
+
project_dir: Path,
|
|
78
78
|
) -> FaceRenderContext:
|
|
79
79
|
"""Resolve a face path and walk for dbt context.
|
|
80
80
|
|
|
81
|
-
``project_dir
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
authoritative; the walk only contributes the dbt project path.
|
|
81
|
+
``project_dir`` is authoritative; the walk only contributes the dbt project
|
|
82
|
+
path. Callers must resolve their project dir first (e.g. via
|
|
83
|
+
``resolve_project_dir(raw_dir)`` at the CLI boundary).
|
|
85
84
|
"""
|
|
86
85
|
if face_path.is_absolute():
|
|
87
86
|
face_file = face_path.resolve()
|
|
88
87
|
elif ".." in face_path.parts:
|
|
89
88
|
face_file = (Path.cwd() / face_path).resolve()
|
|
90
89
|
else:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
else resolve_project_dir(None)
|
|
95
|
-
)
|
|
96
|
-
face_file = (anchor / face_path).resolve()
|
|
97
|
-
|
|
98
|
-
walk_root, dbt_project_path = discover_render_context(
|
|
90
|
+
face_file = (project_dir / face_path).resolve()
|
|
91
|
+
|
|
92
|
+
_, dbt_project_path = discover_render_context(
|
|
99
93
|
face_file.parent,
|
|
100
94
|
discovery_boundary_for_face(face_file.parent, project_dir),
|
|
101
95
|
)
|
|
102
|
-
project_root = project_dir
|
|
96
|
+
project_root = project_dir
|
|
103
97
|
|
|
104
98
|
try:
|
|
105
|
-
scoped_path: Path
|
|
99
|
+
scoped_path: Path = face_file.relative_to(project_root)
|
|
106
100
|
except ValueError:
|
|
107
|
-
|
|
101
|
+
raise ValueError(
|
|
102
|
+
f"Face file {face_file} is outside project_dir {project_root}. "
|
|
103
|
+
f"Pass an explicit --project-dir that contains the face file."
|
|
104
|
+
) from None
|
|
108
105
|
|
|
109
106
|
return FaceRenderContext(
|
|
110
107
|
face_file=face_file,
|
|
@@ -129,18 +126,15 @@ class YamlRenderContext:
|
|
|
129
126
|
|
|
130
127
|
|
|
131
128
|
def build_yaml_render_context(
|
|
132
|
-
project_dir: Path
|
|
129
|
+
project_dir: Path,
|
|
133
130
|
) -> YamlRenderContext:
|
|
134
131
|
"""Walk for dbt context anchored at the given project root.
|
|
135
132
|
|
|
136
|
-
``project_dir
|
|
137
|
-
``
|
|
133
|
+
``project_dir`` is authoritative. Callers must resolve their project dir
|
|
134
|
+
first (e.g. via ``resolve_project_dir(raw_dir)`` at the CLI boundary).
|
|
138
135
|
"""
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
)
|
|
142
|
-
walk_root, dbt_project_path = discover_render_context(anchor, None)
|
|
143
|
-
project_root = anchor if project_dir is not None else walk_root
|
|
136
|
+
project_root = project_dir.resolve()
|
|
137
|
+
_, dbt_project_path = discover_render_context(project_root, None)
|
|
144
138
|
return YamlRenderContext(
|
|
145
139
|
project_root=project_root,
|
|
146
140
|
output_dir=project_root,
|
dataface/ai/llm.py
CHANGED
|
@@ -50,7 +50,8 @@ def _resolve_model(
|
|
|
50
50
|
def _normalize_openai_tools(
|
|
51
51
|
tools: list[dict[str, Any]] | None,
|
|
52
52
|
) -> list[dict[str, Any]]:
|
|
53
|
-
|
|
53
|
+
# None means "use default agent tools"; [] means "no tools, text-only completion".
|
|
54
|
+
source_tools = ALL_TOOLS if tools is None else tools
|
|
54
55
|
if not source_tools:
|
|
55
56
|
return []
|
|
56
57
|
if "input_schema" in source_tools[0]:
|
|
@@ -69,7 +70,8 @@ def _normalize_openai_tools(
|
|
|
69
70
|
def _normalize_anthropic_tools(
|
|
70
71
|
tools: list[dict[str, Any]] | None,
|
|
71
72
|
) -> list[dict[str, Any]]:
|
|
72
|
-
|
|
73
|
+
# None means "use default agent tools"; [] means "no tools, text-only completion".
|
|
74
|
+
source_tools = ALL_TOOLS if tools is None else tools
|
|
73
75
|
if not source_tools:
|
|
74
76
|
return []
|
|
75
77
|
if "input_schema" in source_tools[0]:
|
|
@@ -120,8 +122,14 @@ def _is_anthropic_api_error(exc: Exception) -> bool:
|
|
|
120
122
|
# -- Provider stream adapter ------------------------------------------------
|
|
121
123
|
|
|
122
124
|
|
|
123
|
-
def _iter_anthropic_stream(
|
|
124
|
-
|
|
125
|
+
def _iter_anthropic_stream(
|
|
126
|
+
stream_ctx: Any, usage_sink: Any = None
|
|
127
|
+
) -> Iterator[StreamEvent]:
|
|
128
|
+
"""Parse Anthropic Messages API stream context manager into typed events.
|
|
129
|
+
|
|
130
|
+
``usage_sink``, when given, is called once with the final message's usage
|
|
131
|
+
payload so the client can accumulate token totals.
|
|
132
|
+
"""
|
|
125
133
|
with stream_ctx as stream:
|
|
126
134
|
for event in stream:
|
|
127
135
|
if event.type == "content_block_delta" and event.delta.type == "text_delta":
|
|
@@ -129,6 +137,9 @@ def _iter_anthropic_stream(stream_ctx: Any) -> Iterator[StreamEvent]:
|
|
|
129
137
|
|
|
130
138
|
final_message = stream.get_final_message()
|
|
131
139
|
|
|
140
|
+
if usage_sink is not None:
|
|
141
|
+
usage_sink(final_message.usage)
|
|
142
|
+
|
|
132
143
|
for block in final_message.content:
|
|
133
144
|
if block.type == "tool_use":
|
|
134
145
|
yield ToolCallEvent(
|
|
@@ -144,6 +155,13 @@ class LLMClient(Protocol):
|
|
|
144
155
|
|
|
145
156
|
provider: str
|
|
146
157
|
model: str
|
|
158
|
+
# Cumulative usage across this client's lifetime. Every implementation must
|
|
159
|
+
# maintain these honestly — eval solvers read them to attribute per-case
|
|
160
|
+
# cost/calls. Declared here so callers access them directly (no getattr
|
|
161
|
+
# defaults, which would silently fabricate zeros for a client that forgot them).
|
|
162
|
+
total_input_tokens: int
|
|
163
|
+
total_output_tokens: int
|
|
164
|
+
llm_calls: int
|
|
147
165
|
|
|
148
166
|
def stream_with_tools(
|
|
149
167
|
self,
|
|
@@ -332,6 +350,17 @@ class AnthropicClient:
|
|
|
332
350
|
)
|
|
333
351
|
self.api_key = api_key or os.getenv("ANTHROPIC_API_KEY")
|
|
334
352
|
self._client: Any = None
|
|
353
|
+
# Cumulative token usage + call count (see LLMClient protocol).
|
|
354
|
+
self.total_input_tokens = 0
|
|
355
|
+
self.total_output_tokens = 0
|
|
356
|
+
self.llm_calls = 0
|
|
357
|
+
|
|
358
|
+
def _accumulate_usage(self, usage: Any) -> None:
|
|
359
|
+
"""Add an Anthropic Messages usage payload to the running token totals."""
|
|
360
|
+
if usage is None:
|
|
361
|
+
return
|
|
362
|
+
self.total_input_tokens += getattr(usage, "input_tokens", 0) or 0
|
|
363
|
+
self.total_output_tokens += getattr(usage, "output_tokens", 0) or 0
|
|
335
364
|
|
|
336
365
|
@property
|
|
337
366
|
def client(self) -> Any:
|
|
@@ -404,6 +433,7 @@ class AnthropicClient:
|
|
|
404
433
|
system_prompt: str,
|
|
405
434
|
tools: list[dict[str, Any]] | None = None,
|
|
406
435
|
) -> Iterator[StreamEvent]:
|
|
436
|
+
self.llm_calls += 1
|
|
407
437
|
try:
|
|
408
438
|
yield from _iter_anthropic_stream(
|
|
409
439
|
self.client.messages.stream(
|
|
@@ -412,7 +442,8 @@ class AnthropicClient:
|
|
|
412
442
|
messages=self._messages_to_input(messages),
|
|
413
443
|
tools=_normalize_anthropic_tools(tools),
|
|
414
444
|
max_tokens=4096,
|
|
415
|
-
)
|
|
445
|
+
),
|
|
446
|
+
usage_sink=self._accumulate_usage,
|
|
416
447
|
)
|
|
417
448
|
except Exception as exc:
|
|
418
449
|
if _is_anthropic_api_error(exc):
|
dataface/cli/commands/render.py
CHANGED
|
@@ -8,6 +8,8 @@ from dataface.agent_api import ProjectSession
|
|
|
8
8
|
from dataface.agent_api._paths import (
|
|
9
9
|
build_face_render_context,
|
|
10
10
|
build_yaml_render_context,
|
|
11
|
+
resolve_project_dir,
|
|
12
|
+
resolve_project_dir_from_paths,
|
|
11
13
|
)
|
|
12
14
|
from dataface.agent_api.cache import cache_from_env
|
|
13
15
|
from dataface.agent_api.dashboards import RenderedDashboard
|
|
@@ -119,7 +121,10 @@ def render_command(
|
|
|
119
121
|
if ignore_codes:
|
|
120
122
|
_emit_unknown_code_notices(ignore_codes)
|
|
121
123
|
|
|
122
|
-
|
|
124
|
+
resolved_project_dir = resolve_project_dir_from_paths(
|
|
125
|
+
[face_path.resolve()], project_dir
|
|
126
|
+
)
|
|
127
|
+
ctx = build_face_render_context(face_path, resolved_project_dir)
|
|
123
128
|
output_dir = ctx.output_dir
|
|
124
129
|
|
|
125
130
|
with (
|
|
@@ -208,7 +213,8 @@ def render_command_from_yaml(
|
|
|
208
213
|
if ignore_codes:
|
|
209
214
|
_emit_unknown_code_notices(ignore_codes)
|
|
210
215
|
|
|
211
|
-
|
|
216
|
+
resolved_project_dir = resolve_project_dir(project_dir)
|
|
217
|
+
ctx = build_yaml_render_context(resolved_project_dir)
|
|
212
218
|
output_dir = ctx.output_dir
|
|
213
219
|
|
|
214
220
|
with (
|
|
@@ -3,7 +3,7 @@ dataface/_docs_site.py,sha256=wREocIbQJ9oUfIpQBMCBpNGKZv-w6R0khOg_tSMQTeA,639
|
|
|
3
3
|
dataface/_install_hint.py,sha256=mtNmc3xBoe4qtgsZc7UMpiMq_ajOeUyJ3GixCYzPjtE,1162
|
|
4
4
|
dataface/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
dataface/agent_api/__init__.py,sha256=aQygBBltbxFjhUErS4fJJTsUF2NYrY-2wHxq42ZR7TQ,3497
|
|
6
|
-
dataface/agent_api/_paths.py,sha256=
|
|
6
|
+
dataface/agent_api/_paths.py,sha256=onfFrfW8MIPzRyE0xazGn7-0g06MfuyAZ2FQ3p1-ZXI,4641
|
|
7
7
|
dataface/agent_api/_session_store.py,sha256=viTnMGWNlT0fIKwXmjz3pb95PR1taIrfRq9NOWEMivg,16932
|
|
8
8
|
dataface/agent_api/_state.py,sha256=mD4JsshDhRANhqb2TrR_NLPXsw-dB3m3bi1UnG2jCF0,723
|
|
9
9
|
dataface/agent_api/cache.py,sha256=m1W8jTkGsaDSnnQB9Yncn8QlBwn4prgutVizL0ymqUM,767
|
|
@@ -40,7 +40,7 @@ dataface/ai/context.py,sha256=YxIkDgNYbRzoezC1jiIX3ULVA7ipNh-KrpJzKgvrQAQ,1648
|
|
|
40
40
|
dataface/ai/events.py,sha256=QJZA_t09AU9BLDB63jKwssODoG5l_I1hyRXi0lXas7Y,1161
|
|
41
41
|
dataface/ai/external_mcp.py,sha256=7uClq0PQjX9KkBIkg5HZg4_Ze4VV49lQE0XEcyIeTek,23130
|
|
42
42
|
dataface/ai/generate_sql.py,sha256=uOtgO5oFMmM8uvsrk2owl9so3DGxdN2QSk6MOstZXhA,2394
|
|
43
|
-
dataface/ai/llm.py,sha256=
|
|
43
|
+
dataface/ai/llm.py,sha256=1taZucoFb_LgdnzqXVk8oHwNxHIgBRKs8rUpw3kitPI,16628
|
|
44
44
|
dataface/ai/memories.py,sha256=fua8IJvkomQAatVFhUeSbS-B421ozd6QOpsiOfhpCWs,2608
|
|
45
45
|
dataface/ai/prompts.py,sha256=jzQYccHbBczA_ahkDbbn0o4PGQtZRlgSWTL7bv-Wk8E,6518
|
|
46
46
|
dataface/ai/schema_context.py,sha256=oH2tnIrvuRHSbJ9RtWTdu7MJ5MGC3N6vXDQomkhDJmI,5807
|
|
@@ -68,7 +68,7 @@ dataface/cli/commands/init.py,sha256=H3bf3nE1AcYeMRJtMEEGiCHduBK_1_BllWyn_nJRxU4
|
|
|
68
68
|
dataface/cli/commands/inspect.py,sha256=eN0AdJksPbsiMAn_GNfnr5rekW88zv8MpCJa3R4OtlA,3624
|
|
69
69
|
dataface/cli/commands/mcp_init.py,sha256=bNPTOJzu2EtHTY0oLdJQ8F9N8aPoR4ZCxa_fZtsqsvE,6815
|
|
70
70
|
dataface/cli/commands/query.py,sha256=4d5Mht1dDh6613U-ZR90Ytrs5UkEoFZHvkHii2Ga9SM,15370
|
|
71
|
-
dataface/cli/commands/render.py,sha256=
|
|
71
|
+
dataface/cli/commands/render.py,sha256=gHZ4UiXHrLqgp1tXT6M2fTy8-H3sC3abwp2TFJHoUcM,11882
|
|
72
72
|
dataface/cli/commands/schema.py,sha256=dmHCY3JLpe6pqXM1RF0g83CIomFvhIlk9xknNWVgaWg,16483
|
|
73
73
|
dataface/cli/commands/search.py,sha256=VWty53aifdg1USW7fsjMiE4giXjC4jjfn2NFaoBsdLk,1217
|
|
74
74
|
dataface/cli/commands/serve.py,sha256=-SaYudiPYncijdA52QAhTChQMBB48jyMie5EE7FbnP4,4294
|
|
@@ -519,8 +519,8 @@ mdsvg/renderer.py,sha256=RL09P1uXFxEVSsehzzp5QRts5qGeQ5-rMLn1JIrYWl4,61196
|
|
|
519
519
|
mdsvg/style.py,sha256=RKQATn2C-bymM_5ATZtsNOyyKKakjiVdqLUNrSosTfo,16191
|
|
520
520
|
mdsvg/types.py,sha256=MQlqsUP5y78D8kX0brD-82DkBvaUYdbmkq1U95TnyWA,5093
|
|
521
521
|
mdsvg/utils.py,sha256=CIqFACFaJiM0A_dl-hJXYhRqH-T7ayazP62wgfWGMjw,1866
|
|
522
|
-
dataface-0.1.6.
|
|
523
|
-
dataface-0.1.6.
|
|
524
|
-
dataface-0.1.6.
|
|
525
|
-
dataface-0.1.6.
|
|
526
|
-
dataface-0.1.6.
|
|
522
|
+
dataface-0.1.6.dev76.dist-info/METADATA,sha256=7mxSdfhiakEh_DWtJ-ANtM7hILFWILnS9fu_sOGhiPQ,11454
|
|
523
|
+
dataface-0.1.6.dev76.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
524
|
+
dataface-0.1.6.dev76.dist-info/entry_points.txt,sha256=imfZRsAzmIbDRHW7jqhn0nT6EbYWAyOiuHisxmfVgXs,46
|
|
525
|
+
dataface-0.1.6.dev76.dist-info/licenses/LICENSE,sha256=Iy9gBB2gC8WGQEwHxJd4-huwUvxB6OMOoT3no6emeaQ,11345
|
|
526
|
+
dataface-0.1.6.dev76.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|