Preserve recovery transcripts and add user-approved agent requests
PR and Push Build/Test / build-and-test (push) Successful in 12m0s

Append successful offline recovery with a duplicate-warning marker and retain failed replay sources. Offer newly available microphones through confirmation notifications.

Add project discovery metadata and blocking association approval, plus nonblocking workflow requests that start a separate settings-agent conversation. Include regression tests, OpenSpec changes, and verified local Release startup.
This commit is contained in:
2026-09-25 11:58:34 +02:00
parent e011e36ef7
commit 7b2bcd3631
50 changed files with 2188 additions and 113 deletions
+24 -3
View File
@@ -136,7 +136,9 @@ The tray's fine-grained controls expose `Pause transcription` while a meeting is
On Windows, `Recording:MicrophoneDeviceId` can pin capture to a specific active microphone endpoint id. Leave it blank to follow the Windows default capture endpoint. The tray icon menu also exposes `Microphone`, listing active microphone endpoints with the effective endpoint checked. Selecting a microphone there overrides the configured/default microphone for later recording starts until another microphone is selected or the process exits.
`Recording:MicrophoneMixGain` and `Recording:SystemAudioMixGain` are applied during the final mix and default to `1`. `Recording:TemporaryRecordingsFolder` controls where the temporary mixed WAV is written while the run is active. Temporary WAV files are deleted after the run completes, and stale temporary recordings from interrupted runs are deleted when the application starts. If an Azure Speech meeting cannot drain transcription before `Recording:StopProcessingTimeout`, Meeting Assistant keeps the WAV and writes a durable backlog item under `TemporaryRecordingsFolder\offline-transcription-backlog`. The background backlog worker retries those queued meetings, replays each WAV through a fresh speech pipeline, rewrites the original transcript, completes meeting metadata and summary generation, then removes the backlog item and WAV.
During active capture, including paused transcription, active microphone endpoints are checked once per second. A newly available endpoint produces a Windows notification naming the microphone with Yes/No actions; endpoints already present when capture starts are not offered. Yes changes the shared runtime microphone selection and replaces the current microphone capture, preserving the meeting, system audio, transcription session, and pause state. The selection also applies to later recordings until changed or the process exits. No or an unanswered prompt leaves capture unchanged. Each endpoint is offered at most once per meeting. Prompts become invalid after one minute, when the endpoint disappears, or when that recording stops; a stale notification cannot change a later recording.
`Recording:MicrophoneMixGain` and `Recording:SystemAudioMixGain` are applied during the final mix and default to `1`. `Recording:TemporaryRecordingsFolder` controls where the temporary mixed WAV is written while the run is active. Temporary WAV files are deleted after the run completes, and stale temporary recordings from interrupted runs are deleted when the application starts. If an Azure Speech meeting cannot drain transcription before `Recording:StopProcessingTimeout`, Meeting Assistant keeps the WAV and writes a durable backlog item under `TemporaryRecordingsFolder\offline-transcription-backlog`. The background backlog worker retries those queued meetings and replays each WAV through a fresh speech pipeline. A replay without non-blank speech text leaves the artifacts unchanged and retains the backlog item and WAV for another retry. A usable replay preserves the existing transcript body and appends a recovery section explaining that the full recording was replayed and may duplicate earlier passages; the summary agent receives both the original and recovered text with that explanation. The worker then completes meeting metadata and summary generation and removes the backlog item and WAV.
`Recording:MaxMetadataAttendeeImportCount` limits how many attendees Outlook metadata enrichment imports into meeting-note frontmatter. The default is `30`; when an appointment has more attendees than that, Meeting Assistant still imports title, agenda, and scheduled end time, but leaves attendees empty because large invites are usually presentation-style meetings.
@@ -387,11 +389,30 @@ When enabled on Windows, Meeting Assistant periodically syncs today's Outlook Cl
| `EnableCompaction` | Enables conversation compaction before requests exceed the configured context budget. |
| `CompactionRemainingRatio` | Remaining-context ratio that triggers compaction. |
| `ResponsesCompactPath` | Relative Responses compaction path, usually `responses/compact`. |
| `InitialPrompt` | Optional complete replacement for the default summary-agent system instructions. |
| `InitialPrompt` | Optional replacement for the default base summary instructions. Project metadata and approval guidance is appended to both default and custom prompts. |
After transcription has fully finished, Meeting Assistant automatically runs the summary pipeline for the meeting. The summary agent writes the full markdown summary through `write_summary` and must provide a required `oneliner` value, which is stored in summary frontmatter and must not contain line breaks.
The built-in summary-agent instructions treat assistant context as persistent meeting-specific memory. When the agent encounters an unexpected problem, missing information, or an assumption while summarizing, it appends a concise note through `write_context` so later work on the same meeting can use that history. A configured `Agent:InitialPrompt` completely replaces the built-in instructions, so custom prompts must include equivalent guidance when this behavior is desired.
The built-in summary-agent instructions treat assistant context as persistent meeting-specific memory. When the agent encounters an unexpected problem, missing information, or an assumption while summarizing, it appends a concise note through `write_context` so later work on the same meeting can use that history. A configured `Agent:InitialPrompt` replaces the built-in base instructions, so custom prompts must include equivalent memory guidance when this behavior is desired. Project metadata and approval guidance is always appended.
Every direct subfolder of `Vault:ProjectsFolder` is a project whose ID is its folder name. The summarizer maintains a root `PROJECT.md` for associated projects with YAML frontmatter such as:
```yaml
---
name: Alpha Platform
description: Meeting automation and shared project knowledge.
---
```
The display name comes from `name`; `description` is limited to 256 characters. Missing or malformed metadata falls back to the folder ID and an empty description. Bound project metadata is included in the initial prompt beside any root `AGENTS.md`, including when no instructions file exists. Both default and custom prompts instruct the agent to keep this metadata grounded and current while preserving other frontmatter and body notes.
`list_projects` returns the complete catalog as JSON entries with `id`, `displayname`, and `description`. This grants no file access. Reading, writing, searching, and retrieving historical summaries remain scoped to the meeting note's `projects` field. The summarizer uses its existing `write_projectfile` tool to maintain `PROJECT.md`; invalid resulting metadata is refused before writing.
`request_project_association(project_id, reason)` asks the user through a native Yes/No notification. The reason must be one nonempty line of at most 100 characters. The tool blocks the summarizer until the decision or a ten-minute timeout. Approval adds the canonical ID to the latest meeting note, preserves other metadata and notes, immediately enables project access, and returns the project's metadata and optional `AGENTS.md`. No, timeout, cancellation, or unavailable notifications grant no access. Expired notifications are removed and late actions have no effect. Already associated projects return context without another prompt.
`request_workflow_change(intention, detailed_prompt)` returns requested immediately. The intention is a nonempty single line of at most 100 characters; the detailed prompt should be a self-contained scenario or specification. Its native notification remains valid for ten minutes and can be accepted after the summary completes. Approval opens a separate settings-agent conversation and submits the complete prompt automatically. Declining or expiration opens nothing. Requests are held in memory and canceled on application shutdown. The summarizer itself receives no workflow-editing tools.
Once a stopped meeting reaches summarization, expiration of `Recording:StopProcessingTimeout` returns control while that run continues in the background. It does not cancel a summary waiting for project approval or queue that already-transcribed meeting for offline replay. The approval's own ten-minute deadline remains in effect.
The summary agent can add and remove meeting-note attendees when transcript or OCR evidence is clear. It can override transcript speaker labels only when the evidence is very certain, and it can delete wrongfully matched identities. Final speaker identity learning and candidate updates run after the summary pipeline finishes so they use the summary-refined attendee list and any recorded speaker identity changes.