Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .papercuts/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -530,3 +530,5 @@ symlink with this checkout's own npm ci. Full type-check and lint then passed.
- Electron's `media` permission covers camera as well as microphone; check `mediaType` on permission checks and exact `mediaTypes: ["audio"]` on permission requests instead of treating the permission name as audio-only.
- A green external-review check can race a final inline comment by seconds. Re-read unresolved review threads after the check completes and make the merge command conditional on an empty result rather than chaining inspection and merge unconditionally.
- React effect cleanup marks the hook unmounted before revoking picker authority; reconfiguration needs the replacement effect setup to reset UI ownership, while final unmount must not schedule state recovery.
- A release can contain a fully tested user-facing feature while still hiding it from Finder launches if its main-process capability defaults to an environment-only opt-in. Add a focused default-environment regression whenever changing a shipping feature gate.
- For a default-on environment gate, do not use trimmed-value truthiness to detect absence: an unset variable may enable the default, but explicitly empty or whitespace-only overrides must remain fail-closed.
2 changes: 1 addition & 1 deletion docs/plans/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ This directory is the source of truth for Aiden's implementation plans. The engi
| [Dynamic Model Catalog](dynamic-model-catalog-plan.md) | Implemented | Validated pi.dev overlays, offline `0600` cache hydration, scoped setup refresh, four-hour launch refresh, force refresh, Pi metadata fallback, and Mac/iOS projection ship on pinned Pi 0.84.4. |
| [Generative UI Artifacts](generative-ui-artifacts-plan.md) | Active | Phases 0–6 shipped: chat-scoped `render_artifact`, strict sandboxed preview/export hosts, verified vendored Chart.js/Plotly/KaTeX, permission-aware `/visualize`, crash-recoverable authoritative storage/copies, descriptor-relative workspace reads, one-iframe handoff/expansion, visible failure states, and route-stable Responding/Visualizing activity. Three-agent PR review findings are remediated with focused regression coverage. |
| [Generation Progress Notes](generation-progress-notes-plan.md) | Planned | No implementation yet. |
| [Aiden Live Assistant](gemini-live-assistant-plan.md) | Partial | Extended Thinking, the blue orb, Google model visibility, and session threads are implemented. Local test builds add input/output device selection, connection sounds, and session-authorized direct actions without per-action prompts; native screen-picker and real-Google operator receipts remain open. |
| [Aiden Live Assistant](gemini-live-assistant-plan.md) | Partial | Voice-only Aiden Live ships enabled by default in 0.41.5 with Extended Thinking, the blue duplex orb, device selection, connection sounds, session threads, and session-authorized direct actions. Screen capture remains independently gated pending native-picker acceptance. |
| [Libghostty workspace terminal](libghostty-terminal-plan.md) | Implemented | The workspace drawer uses Ghostty's official `libghostty-vt` WASM (T3-style runtime, PTY trampoline, canvas surface); node-pty sessions are unchanged. Packaged Mac acceptance remains. |
| [Logging and Diagnostics Upgrade](logging-and-diagnostics-upgrade-plan.md) | Implemented | Phases 0–7 are implemented: bounded typed desktop journals, main-owned renderer evidence, local support export/delete, native categorical parity, and CI/release gates. Signed/notarized `v0.35.0` passed packaged diagnostics acceptance; physical-device termination receipts remain. |
| [Long-thread payload upgrades](long-thread-payload-upgrade-plan.md) | Partial | Investigation complete: T3’s O(N²) stdout store does not exist here. No-op `toolRunning` timeline republish is skipped; Remote gzip, stream-journal debounce, chat JSON/attachments, and transcript windowing remain planned. |
Expand Down
7 changes: 4 additions & 3 deletions docs/plans/gemini-live-assistant-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

Status: Partial — Phases 0–4 plus the beta-labeled Aiden Live orb/setup shell and dedicated metadata-only session threads are implemented; authorized macOS screen capture and real Google beta receipts remain operator-owned
Date: 2026-09-15
Voice-default release follow-up (2026-09-17): 0.41.5 exposes ordinary voice-only Aiden Live in normal Finder-launched production builds. The existing `AIDEN_EXPERIMENTAL_GEMINI_LIVE=0`/`false` values remain an incident kill switch. Screen capture is unchanged and stays unavailable unless `AIDEN_EXPERIMENTAL_GEMINI_LIVE_SCREEN=1` is deliberately supplied; the native-picker acceptance receipt remains pending.
Continuous orb follow-up (2026-09-17): active listening/thinking/speaking/acting now share stable Listening + Weaving canvas layers with a slow complementary blend and connection/rest crossfades. Removed visible dock status text (retained screen-reader status). First active click reveals Stop; the second stops, Escape restores the orb, and closing disables duplicate clicks. Sharing/error surfaces remain visible. Added mapping/click-policy regressions; all 230 Live tests, type-check, lint, and standalone browser interaction/motion checks pass. Downloads duplex-review.html uses the actual orb component; the installed notarized app has not been rebuilt for this change.

Release hardening follow-up (2026-09-17): Pullfrog's post-merge review blocked 0.41.4 publication until screen authority is generation-fenced. Exact binding tokens now prevent stale releases from revoking replacements, late picker streams stop after teardown, rejected frame sends revoke capture, and temporary Electron permission handlers admit only audio-only media for the exact document before restoring defaults when the final binding closes. Source Change/Remove is locked across pending provider startup and start failure releases the exact current binding. Adversarial coverage was added for each path.
Expand Down Expand Up @@ -91,9 +92,9 @@ Stop, manual reconnect, and exact-session renderer teardown/late-event fencing.
The UI and main service both keep screen capture unavailable until the native
macOS picker acceptance is recorded. No capture resumes automatically.

The candidate voice-first model is `gemini-3.8-live-extended-thinking`. The beta
remains acceptance-gated with `AIDEN_EXPERIMENTAL_GEMINI_LIVE=1` until the exact
model passes the credentialed Google Live and Computer Use contract.
The voice-first model is `gemini-3.8-live-extended-thinking`. Voice-only Live
ships enabled as a beta; `AIDEN_EXPERIMENTAL_GEMINI_LIVE=0` is the incident
kill switch. Screen capture remains separately acceptance-gated.
Extended Thinking uses explicit `NON_BLOCKING` Computer Use declarations so it
can speak brief progress updates while tools run. Every mutation remains paused
behind a fresh, finalized user-voice “Allow once” or “Deny” decision.
Expand Down
24 changes: 19 additions & 5 deletions main/services/gemini-live/feature-flag.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
geminiLiveScreenEnabled,
} from "./feature-flag.js";

test("Gemini 3.8 Live stays acceptance-gated behind an exact opt-in", () => {
assert.equal(geminiLiveEnabled({}), false);
test("voice-only Gemini 3.8 Live ships on with an explicit kill switch", () => {
assert.equal(geminiLiveEnabled({}), true);
assert.equal(geminiLiveEnabled({ AIDEN_EXPERIMENTAL_GEMINI_LIVE: "true" }), true);
assert.equal(geminiLiveEnabled({ AIDEN_EXPERIMENTAL_GEMINI_LIVE: "1" }), true);
assert.equal(geminiLiveEnabled({ AIDEN_GEMINI_LIVE_REAL_ACCEPTANCE: "1" }), true);
Expand All @@ -21,6 +21,12 @@ test("Gemini 3.8 Live stays acceptance-gated behind an exact opt-in", () => {
const disabled = { AIDEN_EXPERIMENTAL_GEMINI_LIVE: "0" };
assert.equal(geminiLiveEnabled(disabled), false);
assert.equal(experimentalGeminiLiveModel(disabled), null);
const disabledByName = { AIDEN_EXPERIMENTAL_GEMINI_LIVE: " false " };
assert.equal(geminiLiveEnabled(disabledByName), false);
assert.equal(experimentalGeminiLiveModel(disabledByName), null);
assert.equal(geminiLiveEnabled({ AIDEN_EXPERIMENTAL_GEMINI_LIVE: "" }), false);
assert.equal(geminiLiveEnabled({ AIDEN_EXPERIMENTAL_GEMINI_LIVE: " " }), false);
assert.equal(geminiLiveEnabled({ AIDEN_EXPERIMENTAL_GEMINI_LIVE: "enabled" }), false);
assert.equal(
experimentalGeminiLiveModel({
AIDEN_EXPERIMENTAL_GEMINI_LIVE: "true",
Expand All @@ -30,14 +36,14 @@ test("Gemini 3.8 Live stays acceptance-gated behind an exact opt-in", () => {
);
});

test("screen sharing needs both flags and can never outlive the Live gate", () => {
test("screen sharing stays separately opt-in and cannot outlive the Live gate", () => {
const live = { AIDEN_EXPERIMENTAL_GEMINI_LIVE: "1" };
assert.equal(geminiLiveScreenEnabled({}), false);
assert.equal(geminiLiveScreenEnabled(live), false);
assert.equal(
geminiLiveScreenEnabled({ AIDEN_EXPERIMENTAL_GEMINI_LIVE_SCREEN: "1" }),
false,
"the screen flag alone must not admit capture",
true,
"the screen flag admits capture when the default-on voice gate is healthy",
);
assert.equal(
geminiLiveScreenEnabled({ ...live, AIDEN_EXPERIMENTAL_GEMINI_LIVE_SCREEN: "true" }),
Expand All @@ -47,4 +53,12 @@ test("screen sharing needs both flags and can never outlive the Live gate", () =
geminiLiveScreenEnabled({ ...live, AIDEN_EXPERIMENTAL_GEMINI_LIVE_SCREEN: "1" }),
true,
);
assert.equal(
geminiLiveScreenEnabled({
AIDEN_EXPERIMENTAL_GEMINI_LIVE: "0",
AIDEN_EXPERIMENTAL_GEMINI_LIVE_SCREEN: "1",
}),
false,
"the screen gate cannot override the Live incident kill switch",
);
});
15 changes: 7 additions & 8 deletions main/services/gemini-live/feature-flag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@ export const GEMINI_LIVE_MODEL = "gemini-3.8-live-extended-thinking";
export const GEMINI_LIVE_SCREEN_FLAG = "AIDEN_EXPERIMENTAL_GEMINI_LIVE_SCREEN";

/**
* The exact Live + Computer Use contract stays opt-in until a credentialed
* production acceptance receipt exists for this pinned model.
* Voice-only Aiden Live ships enabled. Keep an explicit environment kill
* switch for incident recovery without coupling ordinary voice to the
* separately gated screen-capture path.
*/
export function geminiLiveEnabled(
environment: Readonly<Record<string, string | undefined>> = process.env,
): boolean {
const value = environment[GEMINI_LIVE_FEATURE_FLAG]?.trim().toLowerCase();
return (
value === "1" ||
value === "true" ||
environment.AIDEN_GEMINI_LIVE_REAL_ACCEPTANCE?.trim() === "1"
);
const rawValue = environment[GEMINI_LIVE_FEATURE_FLAG];
if (rawValue === undefined) return true;
const value = rawValue.trim().toLowerCase();
return value === "1" || value === "true";
}

/**
Expand Down
5 changes: 2 additions & 3 deletions main/services/gemini-live/service-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,10 @@ const LIVE_COMPUTER_USE_DESCRIPTION =
let disposeDisplayMediaGuards: (() => void) | null = null;

/**
* The acceptance-gated beta resolves only the recorded
* The voice-only beta resolves only the recorded
* `gemini-3.8-live-extended-thinking` model; it
* never guesses from a normal Gemini chat model or the SDK guide's preview
* string. `AIDEN_EXPERIMENTAL_GEMINI_LIVE=1` is reserved for credentialed
* acceptance and explicit experimental launches until that contract passes.
* string. Screen capture remains independently acceptance-gated.
*/
export const geminiLiveService = new GeminiLiveService({
credentials: piCredentialStore,
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aiden-agent",
"version": "0.41.4",
"version": "0.41.5",
"private": true,
"description": "A macOS AI workspace agent for local and hosted models",
"keywords": [
Expand Down