Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@ All notable changes to DazScript Server are documented here.

## [Unreleased]

### Unified dazpy protocol surface

`DazClient` and `AsyncDazClient` now own registered-script registration and
execution, detailed script/render cancellation, long-poll timeout policy, and
generic server-error mapping through `ServerResponseError`. Status, health,
metrics, request management, exports, and async SSE streams all use the same
typed authentication, connection, timeout, busy, and server-response errors.
This lets integrations depend on dazpy instead of duplicating endpoint URLs,
wire payloads, and error handling.

### Structured async job observation

Async script submissions may name a per-job `reportFile`. The server truncates
it at submission, incrementally ingests its JSONL events while Daz's main thread
is occupied, and exposes one `observation` record through status and result:
structured progress, the most recent 100 log entries with truncation metadata,
and a deduplicated output manifest. Request lists carry a bounded observation
summary. Both `DazClient` and `AsyncDazClient` accept `report_file=` for inline
and file-backed async jobs. Live report ingestion is available on Studio 6;
Studio 4 parses the final report on the main thread after execution returns.

## [2.9.2] - 2026-08-21

### dazpy script-call batching
Expand Down
3 changes: 3 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ Synchronous execution crosses to `handleExecuteRequest()` via
and validate with local reentrant Qt Core values, then submit to mutex-protected
services without blocking on the main thread. Studio 4 must keep submission on
the main thread because `JsonStd::parseObject()` uses `QScriptEngine` there.
The same split applies to structured job reports: Studio 6 may ingest JSONL
from polling workers for live observation, while Studio 4 parses the final
report from `markCompleted()` on the main thread after script execution returns.
Neither path may touch GUI objects, `DzScript`, the DAZ API, or shared mutable
state from a worker. Settings used by an async handler are snapshotted before
the server starts.
Expand Down
50 changes: 48 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,13 @@ async def main():

Requires the optional `httpx` dependency: `pip install dazpy[aio]`.

Both clients also own the complete automation protocol used by integrations:
registered-script registration/execution, request status/result/list/cancel,
render cancellation, health checks, exports, and SSE event streams. Non-2xx
server responses surface as typed `dazpy.exceptions` errors (including
`ServerResponseError` for ordinary protocol rejections), so callers do not
need to construct endpoint URLs or inspect raw HTTP responses.

### `DazClient` connection pooling + `close()`

`DazClient` now issues requests through a pooled `requests.Session` instead
Expand Down Expand Up @@ -1772,7 +1779,33 @@ result = requests.get(f"{BASE}/requests/{req_id}/result?wait=true&timeout=300",
**Purpose:** Submit an inline script or host-side script file for asynchronous execution
**Authentication:** Required (if enabled)

**Request Body:** Same as `POST /execute`
**Request Body:** Same as `POST /execute`, plus optional `reportFile` for
structured job observation.

`reportFile` is an absolute host-side path to a JSONL file owned by this job.
The server truncates it when the request is accepted. The script may then write
one JSON object per line. The path is injected into the script's argument object
as reserved field `getArguments()[0].__dssReportFile`, so callers do not have to
duplicate it inside `args`:

```jsonl
{"type":"progress","value":0.25,"current":1,"total":4,"phase":"render","message":"Plate 1"}
{"type":"log","level":"info","message":"Loaded scene"}
{"type":"output","path":"C:/renders/run/plate-1.png","kind":"image","label":"plate"}
```

Progress events require either `value` (0–1) or `current` plus `total`. Log
events require `message`. Output events require `path`; repeating a path updates
that manifest entry. A `manifest` event may provide an `outputs` array. Use a
unique report file for every job.
`reportFile` may not be the submitted `scriptFile`, because the server owns and
truncates the former before the job is queued.

DAZ Studio 6 ingests report events from polling workers, so progress, logs, and
outputs are visible while the main thread is occupied by the script. DAZ Studio
4's JSON parser is main-thread-only; Studio 4 therefore ingests the final report
after execution returns and does not expose report-driven progress while the job
is still running.

**Response (immediate):**
```json
Expand Down Expand Up @@ -1806,7 +1839,15 @@ result = requests.get(f"{BASE}/requests/{req_id}/result?wait=true&timeout=300",
{
"request_id": "a3f2b891",
"status": "running",
"progress": 0.0,
"progress": 0.25,
"observation": {
"progress": {"value": 0.25, "current": 1, "total": 4, "phase": "render"},
"log_tail": [{"level": "info", "source": "script", "message": "Loaded scene"}],
"log_total": 1,
"log_truncated": false,
"output_manifest": {"count": 0, "outputs": []},
"report_file": "C:/renders/run/job.jsonl"
},
"elapsed_ms": 1240,
"queue_position": 0
}
Expand Down Expand Up @@ -1844,6 +1885,11 @@ result = requests.get(f"{BASE}/requests/{req_id}/result?wait=true&timeout=300",
}
```

Completed, failed, and cancelled results also include `observation`. The log
tail is capped at the newest 100 entries; `log_total` and `log_truncated` make
the loss explicit. Ordinary captured `print()` output is folded into the same
tail at completion while remaining available in the legacy `output` field.

Returns HTTP 404 if the request ID is unknown or has been purged (TTL: 1 hour).

---
Expand Down
Loading