docent-python 0.1.60a0__tar.gz → 0.1.61a0__tar.gz
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.
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/PKG-INFO +1 -1
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/reading.py +40 -2
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/_base.py +1 -1
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/_dql.py +10 -3
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/_readings.py +109 -52
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/reading.py +14 -1
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/pyproject.toml +1 -1
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/uv.lock +1 -1
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/.gitignore +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/LICENSE.md +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/README.md +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/__init__.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/__init__.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/data_models/__init__.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/data_models/exceptions.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/data_models/llm_output.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/llm_cache.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/llm_svc.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/model_registry.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/providers/__init__.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/providers/anthropic.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/providers/common.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/providers/google.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/providers/openai.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/providers/openrouter.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/providers/preference_types.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/providers/provider_registry.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_log_util/__init__.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_log_util/logger.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/__init__.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/_tiktoken_util.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/agent_run.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/chat/__init__.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/chat/content.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/chat/message.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/chat/response_format.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/chat/tool.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/citation.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/feedback.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/formatted_objects.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/judge.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/metadata_util.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/regex.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/transcript.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/util.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/judges/__init__.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/judges/analysis.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/judges/impl.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/judges/runner.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/judges/stats.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/judges/types.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/judges/util/forgiving_json.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/judges/util/meta_schema.json +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/judges/util/meta_schema.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/judges/util/parse_output.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/judges/util/template_formatter.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/judges/util/voting.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/loaders/load_inspect.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/mcp/__init__.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/mcp/__main__.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/mcp/server.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/py.typed +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/samples/__init__.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/samples/load.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/samples/log.eval +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/samples/tb_airline.json +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/__init__.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/_agent_runs.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/_client_util.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/_collections.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/_feedback.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/_labels.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/_results.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/_rubrics.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/_sharing.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/agent_run_writer.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/client.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/integrations/__init__.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/integrations/harbor.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/integrations/inspect.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/integrations/nemogym.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/integrations/util.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/llm_context.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/llm_request.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/sdk/util.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/trace.py +0 -0
- {docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/trace_temp.py +0 -0
|
@@ -2,7 +2,7 @@ from datetime import datetime
|
|
|
2
2
|
from typing import Annotated, Any, Literal, TypeAlias
|
|
3
3
|
from uuid import uuid4
|
|
4
4
|
|
|
5
|
-
from pydantic import BaseModel, Field
|
|
5
|
+
from pydantic import BaseModel, Field, model_validator
|
|
6
6
|
|
|
7
7
|
from docent._llm_util.providers.preference_types import ModelOption
|
|
8
8
|
|
|
@@ -177,6 +177,7 @@ class ReadingStep(BaseModel):
|
|
|
177
177
|
name: str | None = None
|
|
178
178
|
reading_id: str | None = None
|
|
179
179
|
dql_query: str | None = None
|
|
180
|
+
dql_step_alias: str | None = None
|
|
180
181
|
prompt_template_segments: list[Any] | None = None
|
|
181
182
|
context_config: dict[str, Any] | None = None
|
|
182
183
|
model: ModelOption
|
|
@@ -191,7 +192,11 @@ class ReadingStep(BaseModel):
|
|
|
191
192
|
def to_submission(self, *, dql_query: str | None = None) -> "ReadingStepSubmission":
|
|
192
193
|
"""Convert to a ReadingStepSubmission for resolve_reading_entry.
|
|
193
194
|
|
|
194
|
-
Optionally overrides dql_query (e.g. after alias substitution).
|
|
195
|
+
Optionally overrides dql_query (e.g. after alias substitution). The
|
|
196
|
+
stored step's own dql_query may be None when dql_step_alias is set;
|
|
197
|
+
callers are expected to pass the resolved DQL explicitly in that case.
|
|
198
|
+
When a concrete DQL is supplied, clear dql_step_alias so the
|
|
199
|
+
submission continues to satisfy the "exactly one DQL source" contract.
|
|
195
200
|
"""
|
|
196
201
|
return ReadingStepSubmission(
|
|
197
202
|
alias=self.alias,
|
|
@@ -203,6 +208,7 @@ class ReadingStep(BaseModel):
|
|
|
203
208
|
prompt_template_segments=self.prompt_template_segments,
|
|
204
209
|
context_config=self.context_config,
|
|
205
210
|
dql_query=dql_query if dql_query is not None else self.dql_query,
|
|
211
|
+
dql_step_alias=None if dql_query is not None else self.dql_step_alias,
|
|
206
212
|
source_reading_preset_id=self.source_reading_preset_id,
|
|
207
213
|
cache_mode=self.cache_mode,
|
|
208
214
|
)
|
|
@@ -272,10 +278,29 @@ class ReadingStepSubmission(BaseModel):
|
|
|
272
278
|
prompt_template_segments: list[Any] | None = None
|
|
273
279
|
context_config: dict[str, ParameterContextConfig] | None = None
|
|
274
280
|
dql_query: str | None = None
|
|
281
|
+
# References a DqlOnlyStep in the same plan whose rows feed this reading.
|
|
282
|
+
# Mutually exclusive with dql_query for template entries.
|
|
283
|
+
dql_step_alias: str | None = None
|
|
275
284
|
|
|
276
285
|
# Scripted reading fields (mutually exclusive with template fields)
|
|
277
286
|
requests: list[ScriptedRequest] | None = None
|
|
278
287
|
|
|
288
|
+
@model_validator(mode="after")
|
|
289
|
+
def _validate_dql_source(self) -> "ReadingStepSubmission":
|
|
290
|
+
if self.requests is not None:
|
|
291
|
+
if self.dql_query is not None or self.dql_step_alias is not None:
|
|
292
|
+
raise ValueError(
|
|
293
|
+
"Scripted reading submissions must not set dql_query or dql_step_alias"
|
|
294
|
+
)
|
|
295
|
+
return self
|
|
296
|
+
if self.dql_query is not None and self.dql_step_alias is not None:
|
|
297
|
+
raise ValueError("ReadingStepSubmission: set exactly one of dql_query / dql_step_alias")
|
|
298
|
+
if self.dql_query is None and self.dql_step_alias is None:
|
|
299
|
+
raise ValueError(
|
|
300
|
+
"ReadingStepSubmission: template entries must set one of dql_query / dql_step_alias"
|
|
301
|
+
)
|
|
302
|
+
return self
|
|
303
|
+
|
|
279
304
|
|
|
280
305
|
class PresetReadingStepSubmission(BaseModel):
|
|
281
306
|
entry_type: Literal["preset_reading"] = "preset_reading"
|
|
@@ -284,8 +309,21 @@ class PresetReadingStepSubmission(BaseModel):
|
|
|
284
309
|
source_reading_preset_id: str
|
|
285
310
|
user_metadata: dict[str, Any] | None = None
|
|
286
311
|
dql_query: str | None = None
|
|
312
|
+
dql_step_alias: str | None = None
|
|
287
313
|
cache_mode: ReadingCacheMode = "reading"
|
|
288
314
|
|
|
315
|
+
@model_validator(mode="after")
|
|
316
|
+
def _validate_dql_source(self) -> "PresetReadingStepSubmission":
|
|
317
|
+
if self.dql_query is not None and self.dql_step_alias is not None:
|
|
318
|
+
raise ValueError(
|
|
319
|
+
"PresetReadingStepSubmission: set exactly one of dql_query / dql_step_alias"
|
|
320
|
+
)
|
|
321
|
+
if self.dql_query is None and self.dql_step_alias is None:
|
|
322
|
+
raise ValueError(
|
|
323
|
+
"PresetReadingStepSubmission: must set one of dql_query / dql_step_alias"
|
|
324
|
+
)
|
|
325
|
+
return self
|
|
326
|
+
|
|
289
327
|
|
|
290
328
|
class DqlOnlyStepSubmission(BaseModel):
|
|
291
329
|
entry_type: Literal["dql_only"] = "dql_only"
|
|
@@ -174,7 +174,7 @@ class DocentBase:
|
|
|
174
174
|
self._plan_id: str | None = None
|
|
175
175
|
self._flushed_collection_id: str | None = None
|
|
176
176
|
self._pending: list[PendingEntry] = []
|
|
177
|
-
self._alias_counter: int =
|
|
177
|
+
self._alias_counter: int = 1
|
|
178
178
|
self._auto_flush: bool = True
|
|
179
179
|
self._atexit_registered: bool = False
|
|
180
180
|
self._crash_detected: bool = False
|
|
@@ -156,20 +156,27 @@ class DocentDqlMixin(DocentBase):
|
|
|
156
156
|
|
|
157
157
|
return agent_run_ids
|
|
158
158
|
|
|
159
|
-
def list_agent_run_ids(
|
|
159
|
+
def list_agent_run_ids(
|
|
160
|
+
self,
|
|
161
|
+
collection_id: str,
|
|
162
|
+
*,
|
|
163
|
+
apply_base_filter: bool = False,
|
|
164
|
+
) -> list[str]:
|
|
160
165
|
"""Get all agent run IDs for a collection.
|
|
161
166
|
|
|
162
167
|
Args:
|
|
163
168
|
collection_id: ID of the Collection.
|
|
169
|
+
apply_base_filter: Whether to apply the collection view's base filter.
|
|
164
170
|
|
|
165
171
|
Returns:
|
|
166
|
-
str:
|
|
172
|
+
list[str]: Agent run IDs for the collection.
|
|
167
173
|
|
|
168
174
|
Raises:
|
|
169
175
|
requests.exceptions.HTTPError: If the API request fails.
|
|
170
176
|
"""
|
|
171
177
|
url = f"{self._api_url}/{collection_id}/agent_run_ids"
|
|
172
|
-
|
|
178
|
+
params = {"apply_base_filter": "true"} if apply_base_filter else None
|
|
179
|
+
response = self._session.get(url, params=params)
|
|
173
180
|
self._handle_response_errors(response)
|
|
174
181
|
return response.json()
|
|
175
182
|
|
|
@@ -158,8 +158,8 @@ class DocentReadingsMixin(DocentBase):
|
|
|
158
158
|
|
|
159
159
|
# ────────────────────────── Reading Plans ──────────────────────────
|
|
160
160
|
|
|
161
|
-
def _next_alias(self
|
|
162
|
-
alias =
|
|
161
|
+
def _next_alias(self) -> str:
|
|
162
|
+
alias = str(self._alias_counter)
|
|
163
163
|
self._alias_counter += 1
|
|
164
164
|
return alias
|
|
165
165
|
|
|
@@ -222,17 +222,39 @@ class DocentReadingsMixin(DocentBase):
|
|
|
222
222
|
return Path(main_file).name
|
|
223
223
|
return None
|
|
224
224
|
|
|
225
|
-
def query(
|
|
226
|
-
|
|
225
|
+
def query(
|
|
226
|
+
self,
|
|
227
|
+
collection_id: str,
|
|
228
|
+
dql: str,
|
|
229
|
+
*,
|
|
230
|
+
name: str | None = None,
|
|
231
|
+
) -> QueryResult:
|
|
232
|
+
"""Create a lazy DQL query handle backed by a plan step.
|
|
233
|
+
|
|
234
|
+
A corresponding ``dql_only`` step is appended to the pending plan
|
|
235
|
+
immediately so the query is visible in the plan UI, even if the
|
|
236
|
+
QueryResult is never consumed by a reading.
|
|
227
237
|
|
|
228
238
|
Args:
|
|
229
239
|
collection_id: Collection ID.
|
|
230
240
|
dql: DQL query string.
|
|
241
|
+
name: Optional display name for the dql-only step.
|
|
231
242
|
|
|
232
243
|
Returns:
|
|
233
244
|
QueryResult handle. Access attributes to get ColumnRef objects.
|
|
234
245
|
"""
|
|
235
|
-
|
|
246
|
+
alias = self._next_alias()
|
|
247
|
+
resolved_dql = dedent(dql).strip()
|
|
248
|
+
self._enqueue_pending(
|
|
249
|
+
_PendingDqlOnlyStep(
|
|
250
|
+
alias=alias,
|
|
251
|
+
collection_id=collection_id,
|
|
252
|
+
dql_query=resolved_dql,
|
|
253
|
+
name=name,
|
|
254
|
+
)
|
|
255
|
+
)
|
|
256
|
+
self._register_atexit()
|
|
257
|
+
return QueryResult(collection_id, resolved_dql, plan_alias=alias)
|
|
236
258
|
|
|
237
259
|
def read(
|
|
238
260
|
self,
|
|
@@ -289,11 +311,11 @@ class DocentReadingsMixin(DocentBase):
|
|
|
289
311
|
provider=provider, model_name=model_name, reasoning_effort=reasoning_effort
|
|
290
312
|
)
|
|
291
313
|
|
|
292
|
-
alias = self._next_alias(
|
|
314
|
+
alias = self._next_alias()
|
|
293
315
|
handle = Reading(client=self, alias=alias)
|
|
294
316
|
|
|
295
317
|
if prompt_template is not None:
|
|
296
|
-
template_segments,
|
|
318
|
+
template_segments, dql_step_alias, ctx_config, inferred_cid = (
|
|
297
319
|
self._serialize_template_prompt(prompt_template, context_config)
|
|
298
320
|
)
|
|
299
321
|
resolved_cid = collection_id or inferred_cid
|
|
@@ -310,7 +332,8 @@ class DocentReadingsMixin(DocentBase):
|
|
|
310
332
|
cache_mode=cache_mode,
|
|
311
333
|
prompt_template_segments=template_segments,
|
|
312
334
|
context_config=ctx_config,
|
|
313
|
-
dql_query=
|
|
335
|
+
dql_query=None,
|
|
336
|
+
dql_step_alias=dql_step_alias,
|
|
314
337
|
requests=None,
|
|
315
338
|
)
|
|
316
339
|
else:
|
|
@@ -330,6 +353,7 @@ class DocentReadingsMixin(DocentBase):
|
|
|
330
353
|
prompt_template_segments=None,
|
|
331
354
|
context_config=None,
|
|
332
355
|
dql_query=None,
|
|
356
|
+
dql_step_alias=None,
|
|
333
357
|
requests=scripted_reqs,
|
|
334
358
|
)
|
|
335
359
|
|
|
@@ -344,28 +368,27 @@ class DocentReadingsMixin(DocentBase):
|
|
|
344
368
|
) -> tuple[list[Any], str | None, dict[str, ParameterContextConfig] | None, str | None]:
|
|
345
369
|
"""Convert prompt segments into template format.
|
|
346
370
|
|
|
347
|
-
Returns (segments_json,
|
|
371
|
+
Returns (segments_json, dql_step_alias, context_config_dict, collection_id).
|
|
372
|
+
The reading is bound to the single QueryResult used in the prompt via
|
|
373
|
+
its plan alias; if none is present the returned alias is ``None``.
|
|
348
374
|
"""
|
|
349
375
|
segments: list[Any] = []
|
|
350
|
-
|
|
376
|
+
seen_qr: QueryResult | None = None
|
|
351
377
|
inferred_collection_id: str | None = None
|
|
352
378
|
param_configs: dict[str, ParameterContextConfig] = {}
|
|
353
|
-
seen_query_results: dict[int, QueryResult] = {}
|
|
354
379
|
|
|
355
380
|
for seg in prompt:
|
|
356
381
|
if isinstance(seg, str):
|
|
357
382
|
segments.append(dedent(seg))
|
|
358
383
|
elif isinstance(seg, ColumnRef):
|
|
359
384
|
qr = seg.query_result
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
seen_query_results[qr_id] = qr
|
|
363
|
-
if dql_query is not None and dql_query != qr.dql:
|
|
364
|
-
raise ValueError(
|
|
365
|
-
"All ColumnRefs in a prompt must reference the same QueryResult"
|
|
366
|
-
)
|
|
367
|
-
dql_query = qr.dql
|
|
385
|
+
if seen_qr is None:
|
|
386
|
+
seen_qr = qr
|
|
368
387
|
inferred_collection_id = qr.collection_id
|
|
388
|
+
elif qr is not seen_qr:
|
|
389
|
+
raise ValueError(
|
|
390
|
+
"All ColumnRefs in a prompt must reference the same QueryResult"
|
|
391
|
+
)
|
|
369
392
|
|
|
370
393
|
param_name = seg.column_name
|
|
371
394
|
param_type = seg.type_annotation or "unknown"
|
|
@@ -392,7 +415,13 @@ class DocentReadingsMixin(DocentBase):
|
|
|
392
415
|
segments[i] = segments[i].rstrip()
|
|
393
416
|
break
|
|
394
417
|
|
|
395
|
-
|
|
418
|
+
dql_step_alias = seen_qr.plan_alias if seen_qr is not None else None
|
|
419
|
+
return (
|
|
420
|
+
segments,
|
|
421
|
+
dql_step_alias,
|
|
422
|
+
param_configs if param_configs else None,
|
|
423
|
+
inferred_collection_id,
|
|
424
|
+
)
|
|
396
425
|
|
|
397
426
|
def _serialize_scripted_requests(
|
|
398
427
|
self,
|
|
@@ -434,29 +463,32 @@ class DocentReadingsMixin(DocentBase):
|
|
|
434
463
|
return result
|
|
435
464
|
|
|
436
465
|
def show_query_result(self, query_result: QueryResult, *, name: str | None = None) -> None:
|
|
437
|
-
"""
|
|
438
|
-
|
|
439
|
-
The DQL results will be shown in the UI but not persisted.
|
|
466
|
+
"""Deprecated: `client.query(...)` now auto-registers a dql-only step.
|
|
440
467
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
468
|
+
Retained as a no-op for backwards compatibility. If ``name`` is
|
|
469
|
+
provided and the query's dql-only step has no name yet, we update
|
|
470
|
+
it so the preview still gets a human-readable label.
|
|
444
471
|
"""
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
)
|
|
472
|
+
import warnings
|
|
473
|
+
|
|
474
|
+
warnings.warn(
|
|
475
|
+
"show_query_result() is deprecated; client.query() already registers a "
|
|
476
|
+
"dql-only plan step. Pass name= to client.query() to label it.",
|
|
477
|
+
DeprecationWarning,
|
|
478
|
+
stacklevel=2,
|
|
453
479
|
)
|
|
454
|
-
|
|
480
|
+
if name is None or query_result.plan_alias is None:
|
|
481
|
+
return
|
|
482
|
+
for p in self._pending:
|
|
483
|
+
if isinstance(p, _PendingDqlOnlyStep) and p.alias == query_result.plan_alias:
|
|
484
|
+
if p.name is None:
|
|
485
|
+
p.name = name
|
|
486
|
+
break
|
|
455
487
|
|
|
456
488
|
def preset_reading(
|
|
457
489
|
self,
|
|
458
490
|
preset_id: str,
|
|
459
|
-
query_result: QueryResult | None
|
|
491
|
+
query_result: QueryResult | None,
|
|
460
492
|
*,
|
|
461
493
|
name: str | None = None,
|
|
462
494
|
user_metadata: dict[str, Any] | None = None,
|
|
@@ -468,16 +500,19 @@ class DocentReadingsMixin(DocentBase):
|
|
|
468
500
|
|
|
469
501
|
Args:
|
|
470
502
|
preset_id: The reading preset ID to use.
|
|
471
|
-
query_result:
|
|
503
|
+
query_result: QueryResult supplying the preset's input rows.
|
|
472
504
|
name: Optional display name for the step.
|
|
473
505
|
user_metadata: Optional metadata stored on the reading row and used in reading deduplication.
|
|
474
506
|
|
|
475
507
|
Returns:
|
|
476
508
|
A Reading handle that will be populated with results after flush().
|
|
477
509
|
"""
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
510
|
+
if query_result is None:
|
|
511
|
+
raise ValueError("preset_reading requires a QueryResult")
|
|
512
|
+
|
|
513
|
+
alias = self._next_alias()
|
|
514
|
+
collection_id = query_result.collection_id
|
|
515
|
+
dql_step_alias = query_result.plan_alias
|
|
481
516
|
handle = Reading(client=self, alias=alias)
|
|
482
517
|
self._enqueue_pending(
|
|
483
518
|
_PendingPresetReading(
|
|
@@ -487,7 +522,8 @@ class DocentReadingsMixin(DocentBase):
|
|
|
487
522
|
name=name,
|
|
488
523
|
source_reading_preset_id=preset_id,
|
|
489
524
|
user_metadata=user_metadata,
|
|
490
|
-
dql_query=
|
|
525
|
+
dql_query=None,
|
|
526
|
+
dql_step_alias=dql_step_alias,
|
|
491
527
|
cache_mode=cache_mode,
|
|
492
528
|
)
|
|
493
529
|
)
|
|
@@ -507,7 +543,7 @@ class DocentReadingsMixin(DocentBase):
|
|
|
507
543
|
Args:
|
|
508
544
|
label: The group label.
|
|
509
545
|
"""
|
|
510
|
-
alias = self._next_alias(
|
|
546
|
+
alias = self._next_alias()
|
|
511
547
|
self._pending.append(_PendingStepGroup(alias=alias, label=label))
|
|
512
548
|
return StepGroupContext(self._pending, alias)
|
|
513
549
|
|
|
@@ -552,6 +588,7 @@ class DocentReadingsMixin(DocentBase):
|
|
|
552
588
|
prompt_template_segments=p.prompt_template_segments,
|
|
553
589
|
context_config=p.context_config,
|
|
554
590
|
dql_query=p.dql_query,
|
|
591
|
+
dql_step_alias=p.dql_step_alias,
|
|
555
592
|
requests=[ScriptedRequest(**r) for r in p.requests] if p.requests else None,
|
|
556
593
|
)
|
|
557
594
|
entries.append(entry)
|
|
@@ -565,6 +602,7 @@ class DocentReadingsMixin(DocentBase):
|
|
|
565
602
|
source_reading_preset_id=p.source_reading_preset_id,
|
|
566
603
|
user_metadata=p.user_metadata,
|
|
567
604
|
dql_query=p.dql_query,
|
|
605
|
+
dql_step_alias=p.dql_step_alias,
|
|
568
606
|
cache_mode=p.cache_mode,
|
|
569
607
|
)
|
|
570
608
|
)
|
|
@@ -675,6 +713,13 @@ class DocentReadingsMixin(DocentBase):
|
|
|
675
713
|
|
|
676
714
|
_FLUSH_TIMEOUT_SECONDS = 600
|
|
677
715
|
|
|
716
|
+
@staticmethod
|
|
717
|
+
def _format_step_label(name: str | None, alias: str, default: str) -> str:
|
|
718
|
+
"""Format a step label that always includes the alias."""
|
|
719
|
+
if name:
|
|
720
|
+
return f"{name} [${alias}]"
|
|
721
|
+
return f"{default} [${alias}]"
|
|
722
|
+
|
|
678
723
|
def _preview_and_wait(
|
|
679
724
|
self,
|
|
680
725
|
*,
|
|
@@ -690,14 +735,17 @@ class DocentReadingsMixin(DocentBase):
|
|
|
690
735
|
for es in submit_response.entry_statuses:
|
|
691
736
|
if es.entry_type == "dql_only":
|
|
692
737
|
if es.status == "cached" and es.dql_preview is not None:
|
|
693
|
-
self._log_dql_preview(pending_names.get(es.alias), es.dql_preview)
|
|
738
|
+
self._log_dql_preview(pending_names.get(es.alias), es.alias, es.dql_preview)
|
|
694
739
|
elif es.status != "cached":
|
|
695
740
|
unsettled_dql_aliases[es.alias] = es
|
|
696
741
|
|
|
697
742
|
elif es.entry_type == "reading":
|
|
698
743
|
if es.status == "cached":
|
|
699
744
|
self._log_reading_preview(
|
|
700
|
-
pending_names.get(es.alias),
|
|
745
|
+
pending_names.get(es.alias),
|
|
746
|
+
es.alias,
|
|
747
|
+
es.result_count,
|
|
748
|
+
es.result_preview,
|
|
701
749
|
)
|
|
702
750
|
else:
|
|
703
751
|
unsettled_reading_aliases.add(es.alias)
|
|
@@ -776,11 +824,15 @@ class DocentReadingsMixin(DocentBase):
|
|
|
776
824
|
collection_id,
|
|
777
825
|
step.reading_id,
|
|
778
826
|
pending_names.get(step.alias),
|
|
827
|
+
step.alias,
|
|
779
828
|
reading_handles.get(step.alias),
|
|
780
829
|
)
|
|
781
830
|
elif step.alias in pending and step.derived_status == "failed":
|
|
782
831
|
self._logger.warning(
|
|
783
|
-
"Step %s failed",
|
|
832
|
+
"Step %s failed",
|
|
833
|
+
self._format_step_label(
|
|
834
|
+
pending_names.get(step.alias), step.alias, "Reading"
|
|
835
|
+
),
|
|
784
836
|
)
|
|
785
837
|
pending.discard(step.alias)
|
|
786
838
|
if not pending:
|
|
@@ -796,6 +848,7 @@ class DocentReadingsMixin(DocentBase):
|
|
|
796
848
|
collection_id,
|
|
797
849
|
event.reading_id,
|
|
798
850
|
pending_names.get(event.step_alias),
|
|
851
|
+
event.step_alias,
|
|
799
852
|
reading_handles.get(event.step_alias),
|
|
800
853
|
result_count=event.result_count,
|
|
801
854
|
)
|
|
@@ -809,9 +862,11 @@ class DocentReadingsMixin(DocentBase):
|
|
|
809
862
|
)
|
|
810
863
|
|
|
811
864
|
elif isinstance(event, PlanStepFailedEvent) and event.step_alias in pending:
|
|
812
|
-
|
|
865
|
+
label = self._format_step_label(
|
|
866
|
+
pending_names.get(event.step_alias), event.step_alias, "Reading"
|
|
867
|
+
)
|
|
813
868
|
msg = event.error.message if event.error else "unknown error"
|
|
814
|
-
self._logger.warning("Step %s failed: %s",
|
|
869
|
+
self._logger.warning("Step %s failed: %s", label, msg)
|
|
815
870
|
pending.discard(event.step_alias)
|
|
816
871
|
|
|
817
872
|
elif isinstance(event, PlanJobCancelledEvent):
|
|
@@ -873,7 +928,7 @@ class DocentReadingsMixin(DocentBase):
|
|
|
873
928
|
truncated=result.get("truncated", False),
|
|
874
929
|
row_count=result.get("row_count", 0),
|
|
875
930
|
)
|
|
876
|
-
self._log_dql_preview(name, preview)
|
|
931
|
+
self._log_dql_preview(name, alias, preview)
|
|
877
932
|
return result
|
|
878
933
|
break
|
|
879
934
|
except Exception:
|
|
@@ -885,11 +940,12 @@ class DocentReadingsMixin(DocentBase):
|
|
|
885
940
|
collection_id: str,
|
|
886
941
|
reading_id: str | None,
|
|
887
942
|
name: str | None,
|
|
943
|
+
alias: str,
|
|
888
944
|
handle: Reading | None,
|
|
889
945
|
result_count: int | None = None,
|
|
890
946
|
) -> None:
|
|
891
947
|
"""Fetch results for a just-completed step, log preview, populate handle."""
|
|
892
|
-
label = name
|
|
948
|
+
label = self._format_step_label(name, alias, "Reading")
|
|
893
949
|
if reading_id is None:
|
|
894
950
|
self._logger.info("%s: completed", label)
|
|
895
951
|
return
|
|
@@ -913,14 +969,14 @@ class DocentReadingsMixin(DocentBase):
|
|
|
913
969
|
else:
|
|
914
970
|
self._logger.info("%s: completed%s", label, count_str)
|
|
915
971
|
|
|
916
|
-
def _log_dql_preview(self, name: str | None, dql_preview: Any) -> None:
|
|
972
|
+
def _log_dql_preview(self, name: str | None, alias: str, dql_preview: Any) -> None:
|
|
917
973
|
"""Log a DQL result preview to stdout."""
|
|
918
974
|
from docent.data_models.reading import DqlPreview
|
|
919
975
|
|
|
920
976
|
if isinstance(dql_preview, dict):
|
|
921
977
|
dql_preview = DqlPreview.model_validate(dql_preview)
|
|
922
978
|
|
|
923
|
-
label = name
|
|
979
|
+
label = self._format_step_label(name, alias, "DQL")
|
|
924
980
|
cols = dql_preview.columns
|
|
925
981
|
rows = dql_preview.rows
|
|
926
982
|
truncated = dql_preview.truncated
|
|
@@ -963,11 +1019,12 @@ class DocentReadingsMixin(DocentBase):
|
|
|
963
1019
|
def _log_reading_preview(
|
|
964
1020
|
self,
|
|
965
1021
|
name: str | None,
|
|
1022
|
+
alias: str,
|
|
966
1023
|
result_count: int | None,
|
|
967
1024
|
result_preview: list[Any] | None,
|
|
968
1025
|
) -> None:
|
|
969
1026
|
"""Log a reading result preview to stdout."""
|
|
970
|
-
label = name
|
|
1027
|
+
label = self._format_step_label(name, alias, "Reading")
|
|
971
1028
|
count_str = f" ({result_count} results)" if result_count is not None else ""
|
|
972
1029
|
self._logger.info("%s: cached%s", label, count_str)
|
|
973
1030
|
if result_preview:
|
|
@@ -76,11 +76,16 @@ class QueryResult:
|
|
|
76
76
|
"""Lazy handle for a DQL query, returned by client.query().
|
|
77
77
|
|
|
78
78
|
Attribute access returns ColumnRef objects for use in prompt templates.
|
|
79
|
+
Each QueryResult is bound to a dql-only step in the plan (identified by
|
|
80
|
+
`_plan_alias`); when a ColumnRef backed by this result is used in a
|
|
81
|
+
reading's prompt_template, that reading's submission references the
|
|
82
|
+
dql-only step via `dql_step_alias` rather than embedding the DQL directly.
|
|
79
83
|
"""
|
|
80
84
|
|
|
81
|
-
def __init__(self, collection_id: str, dql: str) -> None:
|
|
85
|
+
def __init__(self, collection_id: str, dql: str, *, plan_alias: str | None = None) -> None:
|
|
82
86
|
self._collection_id = collection_id
|
|
83
87
|
self._dql = dql
|
|
88
|
+
self._plan_alias = plan_alias
|
|
84
89
|
|
|
85
90
|
@property
|
|
86
91
|
def collection_id(self) -> str:
|
|
@@ -90,6 +95,10 @@ class QueryResult:
|
|
|
90
95
|
def dql(self) -> str:
|
|
91
96
|
return self._dql
|
|
92
97
|
|
|
98
|
+
@property
|
|
99
|
+
def plan_alias(self) -> str | None:
|
|
100
|
+
return self._plan_alias
|
|
101
|
+
|
|
93
102
|
def __getattr__(self, name: str) -> ColumnRef:
|
|
94
103
|
if name.startswith("_"):
|
|
95
104
|
raise AttributeError(name)
|
|
@@ -204,6 +213,7 @@ class _PendingReading:
|
|
|
204
213
|
prompt_template_segments: list[Any] | None,
|
|
205
214
|
context_config: dict[str, ParameterContextConfig] | None,
|
|
206
215
|
dql_query: str | None,
|
|
216
|
+
dql_step_alias: str | None = None,
|
|
207
217
|
# Scripted path
|
|
208
218
|
requests: list[dict[str, Any]] | None,
|
|
209
219
|
) -> None:
|
|
@@ -220,6 +230,7 @@ class _PendingReading:
|
|
|
220
230
|
self.prompt_template_segments = prompt_template_segments
|
|
221
231
|
self.context_config = context_config
|
|
222
232
|
self.dql_query = dql_query
|
|
233
|
+
self.dql_step_alias = dql_step_alias
|
|
223
234
|
self.requests = requests
|
|
224
235
|
|
|
225
236
|
|
|
@@ -248,6 +259,7 @@ class _PendingPresetReading:
|
|
|
248
259
|
source_reading_preset_id: str,
|
|
249
260
|
user_metadata: dict[str, Any] | None,
|
|
250
261
|
dql_query: str | None,
|
|
262
|
+
dql_step_alias: str | None = None,
|
|
251
263
|
cache_mode: ReadingCacheMode = "reading",
|
|
252
264
|
) -> None:
|
|
253
265
|
self.alias = alias
|
|
@@ -257,6 +269,7 @@ class _PendingPresetReading:
|
|
|
257
269
|
self.source_reading_preset_id = source_reading_preset_id
|
|
258
270
|
self.user_metadata = user_metadata
|
|
259
271
|
self.dql_query = dql_query
|
|
272
|
+
self.dql_step_alias = dql_step_alias
|
|
260
273
|
self.cache_mode: ReadingCacheMode = cache_mode
|
|
261
274
|
|
|
262
275
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/data_models/exceptions.py
RENAMED
|
File without changes
|
{docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/data_models/llm_output.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/providers/preference_types.py
RENAMED
|
File without changes
|
{docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/_llm_util/providers/provider_registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docent_python-0.1.60a0 → docent_python-0.1.61a0}/docent/data_models/chat/response_format.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|