Skip to content

feat(dgw): generate a session log with AI - #2008

Draft
irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 3 commits into
feat/task-apifrom
feat/ai-log-task
Draft

irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 3 commits into
feat/task-apifrom
feat/ai-log-task

Conversation

@irvingoujAtDevolution

@irvingoujAtDevolution irvingouj@Devolutions (irvingoujAtDevolution) commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Fills in the ai-log task: DVLS starts it, Gateway turns the session's terminal recording into text, asks the AI what the user did, and adds the answer as a new ai-analysis-{n}.slog artifact in the manifest (artifacts, from #2003).

  • .cast and .trp, read as a stream (new TrpOutputReader), so memory is bounded by the chunk size, not the recording size; WebM fails as unsupported for now
  • chunks go to a task workspace under <RecordingPath>/.provisioner-tasks/<task-id>/ (same access as recordings), deleted when the task ends and cleaned up at startup
  • each chunk's answer is checkpointed, so a retry only re-sends the chunks that didn't finish; an answer cut at the output limit splits the chunk in half and retries
  • only output is sent to the AI, never keystrokes; ANSI stripped, lines prefixed with [seconds]
  • the log uses the shipped .slog format, session.start gets source: "ai", model, promptVersion; progress shows as running { step: "describing", done, total }
  • the recording is read through the recording manager (get_finished, sessions still recording are refused) and the log is copied into an artifact from feat(dgw): list Gateway-generated artifacts in the recording manifest #2003 (add_artifact)

Also adds Error::Truncated to the AI crate (#2005) for answers cut at the token limit (finish_reason: length / stop_reason: max_tokens).

Tested: tasks 15/15 (end-to-end against a mock provider incl. resume + no key in any file), lib tasks:: + recording:: + artifacts:: + api::jrec:: 55/55, gateway_ai 12/12, dvls_compatibility 24/24. A real run with OpenAI gpt-6-luna on a 9-min Ubuntu recording passed before the streaming rework; not re-run yet.

Stacked on #2007.

🤖 Generated with Claude Code

irvingouj@Devolutions (irvingoujAtDevolution) added a commit that referenced this pull request Sep 30, 2026
…#2003)

Lets Gateway attach its own non-recording artifacts (AI analysis first)
to a session recording, without breaking released players, which treat
every `files` entry as playable.

- the manifest gets an `artifacts` object next to `files`, hard-typed
per kind (only `ai-analysis` today):
  ```json
  {
"files": [ { "fileName": "recording-0.webm", "startTime": 1787255035,
"duration": 25 } ],
"artifacts": { "ai-analysis": [ { "fileName": "ai-analysis-0.slog" } ] }
  }
  ```
- artifacts are written by Gateway only, like recordings:
`add_artifact(id, kind)` has the recording manager create the next
`<kind>-N.<ext>` in the session folder, list it and return its path, and
the caller writes into it; it fails when the session has no recording,
so a deleted recording is never recreated. There is no artifact push, so
a push token can't upload one. Nothing calls it yet: the first caller is
the AI log task in #2008
- JREC push is unchanged, `slog` included: AD console `.slog` is that
session's recording and stays in `files`
- artifacts stay out of the recording lifecycle: no recording policy,
disconnect TTL, `/shadow` or duration handling
- an artifact can be added while a recording is being pushed; the
recording re-reads the manifest on disconnect, so neither entry is lost
- `artifacts` is omitted when empty, so existing manifests are
byte-for-byte the same
- session ZIP downloads include artifacts

Design notes: `devolutions-gateway/src/recording.intent.md`.

Tested: `artifacts::` + `recording::` + `api::jrec::` 22/22,
`dvls_compatibility` 24/24.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The packet decoding is shared with the live stream decoder, so a
finished recording can be turned into asciicast without tailing it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Runs the ai-log task end to end: streams the terminal recording into chunk
files in a task workspace, describes each chunk with the AI (checkpointed so a
retry resumes, splitting a chunk when the answer is cut at the output limit),
writes the .slog and copies it into a new `ai-analysis` artifact from the
recording manager (`add_artifact`, #2003). The task reads a finished recording
through the recording manager (`get_finished`). Also regenerates the ai-log
substate docs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The AI crate now reports the model that answered and the tokens each
request used, but the ai-log task dropped both. Task records are kept
for audit, and AI budgets will need the token counts.

Each chunk checkpoint now holds the reported model and the token usage
next to the actions, so a retry keeps the counts of the chunks it does
not ask again. Answers cut at the output limit and asked again in two
halves count too. The task result adds the model and the total usage,
which is absent when the provider did not report it for every request.
The .slog names the reported model, usually a dated version of the
requested one, and falls back to the requested model.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant