Skip to content

feat(ai): say "source":"ai" on every line of the AI log - #2130

Merged
irvingouj@Devolutions (irvingoujAtDevolution) merged 2 commits into
feat/provisioning-task-secretsfrom
feat/ai-log-source-every-line
Oct 22, 2026
Merged

irvingouj@Devolutions (irvingoujAtDevolution) merged 2 commits into
feat/provisioning-task-secretsfrom
feat/ai-log-source-every-line

Conversation

@irvingoujAtDevolution

@irvingoujAtDevolution irvingouj@Devolutions (irvingoujAtDevolution) commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Only session.start of the AI log said "source":"ai". Now every line does, so a caller that shows the AI lines next to other logs, or keeps only some of them, can still tell where each line came from.

The crate intent states it, along with the model and prompt versions that session.start already carries. The intent wording is mine.

Split out of #2118 so that one stays about the language and the summary. It sits on #2058 only for the stack order; there's no code dependency.

Tests: cargo test -p devolutions-gateway-ai passes (99 unit, 28 provider tests); clippy is clean.

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The localized change matches its stated purpose, covers every event type, and has no unresolved findings.

No open issues 🎉

What changed in this PR

Makes every AI session-log line identifiable when logs are mixed or filtered.

Changes:

  • Sets "source":"ai" in the shared entry constructor and updates regression tests.
  • Documents per-line attribution and existing session-start metadata in the crate intent.
File Description
crates/​devolutions-gateway-ai/​src/​recording_analysis/​slog.rs Adds AI attribution to every entry; tests logs with and without actions.
crates/​devolutions-gateway-ai/​INTENT.md Documents the log format and attribution requirement.

Review effort: Balanced

Only `session.start` said where the log comes from. A caller that shows
the AI log next to other logs, or keeps only some of its lines, could no
longer tell those lines apart. Every line now carries it.

The crate intent states it, with the model and prompt versions already on
`session.start`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Gateway is the standard for what an AI `.slog` holds, since a
Gateway release is far harder to ship than a log player. A flat entry
let any line carry any optional field. Each event is now its own
variant with exactly its fields, and the source is a type whose only
value is `ai`.

The test compares JSON values instead of exact text, since key order is
free, and cites the crate intent and the player's sample log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@irvingoujAtDevolution
irvingouj@Devolutions (irvingoujAtDevolution) merged commit 64ea2d3 into master Oct 22, 2026
48 checks passed
@irvingoujAtDevolution
irvingouj@Devolutions (irvingoujAtDevolution) deleted the feat/ai-log-source-every-line branch October 22, 2026 17:48
irvingouj@Devolutions (irvingoujAtDevolution) added a commit that referenced this pull request Oct 22, 2026
…mary (#2118)

The AI analysis now writes in the language the caller asks for and ends
with a summary. AI crate only.

- New `Language` type: any text of 1 to 10 characters, like `fr-CA`,
`zh-Hant-TW` or `français`. `Language::new` refuses anything else, so a
bad value never reaches a prompt, and the short limit leaves little room
to slip in instructions. It reads and writes itself as a JSON string, so
a caller can store it. Without one, the prompts ask for English.
`AnalyzeRecording`, the two action purposes and the summary all take it.
- New purpose `session_summary` (`AiClient::summarize_session`): one
extra request after the actions, only when there are actions. Its tokens
count in the usage. The summary goes in `summary` on the AI log's
`session.end`.
- A summary that fails for good fails the analysis, like any other step:
no log without it. A transient failure is retried, and the retry resumes
from the described chunks.
- `session.start` names the model, the prompt versions and the language.
- A retry with another language starts over instead of reusing the
working files.

## Why a hashed prompt version

Each `PROMPT_VERSION` is the purpose name plus the FNV-1a hash of its
prompt and language rule, computed at compile time, like
`session-actions-3f9a1c2b7e4d0a51`. A hand-bumped number drifts as soon
as someone edits a prompt and forgets it; a hash can't. The language
stays out of the hash and goes on `session.start` instead, so one prompt
keeps one version in every language. The analysis reports
`<actions>+<summary>`.

The crate intent states all of this. The intent wording is mine.

## Where to look hardest

`prompt_version!` and `fnv1a` in `client.rs`, and the summary step at
the end of `recording_analysis/mod.rs`.

Known limit: the summary sends all actions in one request, so a very
long session could go over the model's context window.

Stacked on #2130 (`source` on every line). #2117 is closed: the language
no longer comes from the producer's events log.

Tests: `cargo test -p devolutions-gateway-ai` passes (113 unit, 28
provider tests); clippy is clean.

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.

3 participants