Repository navigation
Conversation
…r (STUDIO A-18) The sidebar's picker lists the signed-in person's deployments (ai-agents GET /apps/deployments) under "Your applications" beside the runtimes; one kept always on, on a running runtime, is talked to with agent-runtimes' <Chat protocol="ag-ui"> on the session API (<kept url>/api/v1/apps/agents/ <agent>/ag-ui/, each thread a session), the others say why not. - The view never holds the person's token: the network bridge lends it only to the requests under the prefixes the provider gives (the kept runtimes, ai-agents' Tool Approvals, Spacer's items). - The Appspec is read from the application's Spacer item: an application that takes only a signed user (deployment.embedded.host.user: signed, D-21) is refused in a sentence (no route signs for the person, and the extension does not hold the deployment's secret). - host_context (D-10) is given when the deployed version names what its host passes and a rule lets it run: page is the editor's open file (path, language, text up to 20,000 characters, selection), read only when the agent asks; user the person signed in, as a claim. - Approvals (R-05): the agent's pending Tool Approvals polled while open and answered in the chat's approval banner (approve / reject). - The transcript's lines (A-06) under the chat: "Desk -> odoo-accounting: tool", "its runtime" for a tool of no connection. Pure logic in src/chat/appChat.ts, tested by webview/test/appChat.test.ts (vitest, 18). README: Talk to your agent.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Deployment validation, authorization matching, and picker error handling contain correctness and privacy issues.
Review effort: Balanced
Findings: 1
Open (5)
Reject deployments without a valid positive integer version · New Reject deployments unless state is exactly live · New Compare URL prefixes using canonicalized href values · New Preserve closed deployment choices and their explanations · New Do not hide usable applications when runtime listing fails · New
What changed in this PR
Adds deployed-application agents to the Agent Chat sidebar, including AG-UI sessions, approvals, host context, and request signing.
Changes:
- Adds deployment discovery and application selection.
- Integrates AG-UI chat, tool approvals, editor context, and transcripts.
- Adds scoped authentication logic and unit tests.
| File | Description |
|---|---|
README.md |
Documents deployed-agent chat. |
cspell.json |
Adds feature terminology. |
src/bridges/agentChatNetworkBridge.ts |
Injects scoped bearer authorization. |
src/chat/README.md |
Documents application-chat logic. |
src/chat/appChat.ts |
Implements deployment, host-context, approval, and signing logic. |
src/providers/agentChatViewProvider.ts |
Loads deployments and handles editor context. |
webview/agentChat/App.tsx |
Adds applications to the agent picker. |
webview/agentChat/AppChat.tsx |
Renders deployed-agent conversations. |
webview/agentChat/README.md |
Documents the webview integration. |
webview/agentChat/index.tsx |
Handles deployment and editor-context messages. |
webview/test/appChat.test.ts |
Tests the pure application-chat logic. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| const version = Number(deployment.version); | ||
| return { | ||
| kind: "talk", | ||
| handle: { | ||
| uid, | ||
| appUid: text(deployment.app_uid), | ||
| name, | ||
| version: | ||
| Number.isFinite(version) && version > 0 ? Math.trunc(version) : 1, | ||
| target: text(deployment.target) || "hosted", | ||
| slug: text(deployment.slug), | ||
| url: base(url), | ||
| agentId, | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Fixed in 60f213e: an absent or malformed version (not a positive integer) closes the deployment with a sentence — never defaulted. And only the deployed revision decides anything: revisionRefusal closes the chat when the Spacer item's revision differs, so host_context is never given on a guess.
| if (deployment.state === "paused") { | ||
| return { kind: "closed", uid, name, why: `${name} is paused.` }; | ||
| } |
There was a problem hiding this comment.
Fixed in 60f213e: offered only when state === "live" exactly; paused, any other state and a missing one are closed with their sentence (same in Desktop and JupyterLab).
| return prefixes.some((prefix) => { | ||
| try { | ||
| return ( | ||
| new URL(prefix).origin === target.origin && href.startsWith(prefix) | ||
| ); | ||
| } catch { | ||
| return false; | ||
| } | ||
| }); |
There was a problem hiding this comment.
Fixed in 60f213e: the comparison is against new URL(prefix).href, so https://R1.DATALAYER.RUN or :443 spellings match; tested in webview/test/appChat.test.ts.
| const talkable = useMemo( | ||
| () => | ||
| (deployments ?? []).flatMap((choice) => | ||
| choice.kind === "talk" ? [choice.handle] : [], | ||
| ), |
There was a problem hiding this comment.
Fixed in 60f213e: closed choices stay in the picker as disabled options under Not available here, each with its why (also as the option's title), and are listed under the empty state too.
| // No agents available. | ||
| if (agents.length === 0) { | ||
| // No agents, and no application to talk to. | ||
| if (agents.length === 0 && talkable.length === 0) { |
There was a problem hiding this comment.
Fixed in 60f213e: a runtime-listing failure is fatal only when no deployment is talkable; otherwise the applications stay pickable and the error is said beside the picker.
📦 Extension Build Ready (Universal VSIX)!Download the extension (works on all platforms):
|
…d desktop#15 (STUDIO A-18)
- Signed users (D-21): an application whose Appspec says
deployment.embedded.host.user: signed is no longer refused. The view asks
the extension host (user-token-request); the host asks ai-agents
(POST /apps/deployments/{uid}/user-token) with the person's token, keeps
the user token and puts it in the body of each run of that deployment
(forwardedProps.loop.user_token) as the network bridge sends it: neither
token reaches the webview.
- A deployment with no version, or a malformed one, is closed with a
sentence, never defaulted to 1; offered only when state is exactly live.
- Only the deployed version decides: an Appspec read at another revision
is refused (revisionRefusal), for who the user is and host_context alike.
- A signed prefix is compared in its canonical spelling (new URL(prefix)
.href), so https://R1.DATALAYER.RUN or :443 still match.
- The closed choices stay in the picker, disabled, each with why; the
empty list's sentence covers every reason (noneTalkableSentence).
- A runtime-listing failure no longer hides the applications: it is fatal
only when none can be talked to, and is said beside the picker otherwise.
- A refresh keeps the deployment picked and takes its newest handle
(pickedHandleOf), memoized on what is talked to (talkableKeyOf).
- ai-agents has its own setting, datalayer.services.aiAgentsUrl (core's
aiAgentsUrl), no longer the runtimes' URL.
- CSP: the Agent Chat webview's connect-src stays the webview's own source;
every request goes through the extension host's bridge.
- The JSDoc the hook's eslint asks for, in appChat.ts and the provider.
Tests: webview/test/appChat.test.ts (vitest, 24).
…cations (STUDIO A-18) Off, the Agent Chat sidebar lists no deployment, asks ai-agents nothing, never reads the open file and never opens AppChat; the runtimes' chat is unchanged. On, deployments are listed as before, one not kept always on listed as closed with why. Fixes the settings validator test for aiAgentsUrl and the spell check.
… seven verbs (VSCODE VS-02, VS-04, VS-03, VS-05, VS-12) - VS-02: a local runtime per workspace folder (loop serve --host 127.0.0.1 --port 0, started when asked, never at activation), loop found on datalayer.local.loopPath, PATH, uv tool's and pipx's bins and judged against 1.5.66, refused in a sentence naming uv tool install 'agent-runtimes[shield]' with Copy; the port from its first line, /health awaited, its output in the Datalayer: Local runtime channel; the trimmed environment plus the harnesses' declared credentials by name (the environment first, the secret storage second), the folder as AGENT_RUNTIMES_WORKSPACE_ROOT, the file session store, the token and IAM when signed in; stopped on deactivation, on Datalayer: Stop the Local Runtime and when the folder closes; listed as a place in the chat's picker (place: local, no token lent) - VS-04: the Sessions view (datalayerSessions, between Spaces and Agents): the person's sessions on Datalayer (ai-agents GET /apps/sessions?opened_by=) and on this machine (each local runtime's GET /api/v1/apps/sessions) grouped by place then application, each row as loop sessions list prints it (state with the turn phase as its icon, agent and harness, turns, lineage, not held); a filter by application, state and title; the archived hidden; refreshed on open, on a sign-in, on a local runtime's start or stop and by the title's button, never polled; an unreachable place in one row; a row opens the session in the chat through datalayer.internal.agentChat.openSession once the provider registers it - VS-03: the harness check: the catalogue from the local runtime's GET /api/v1/harnesses (agent-runtimes 2c3d980e, the next release) or loop harnesses parsed (boxed); node and its version against the register, git, the pinned adapter in the Shield's prefix, the credential in the environment or context.secrets (typed once, never in settings, never shown), the terms (an API-key-only harness refuses a subscription login); agent-shield setup --harness <id> offered in a terminal with the command shown whole - VS-05: Resume, Switch Agent…, Clone from Here…, Export…, Import…, Rename…, Archive, End from the tree, calling appSessionsClient from the extension host on the runtime that answers for the session (a local place unsigned; on Datalayer the runtime it runs on, signed), every refusal the runtime's sentence; Reveal in Explorer and Open in the Studio - VS-12: a Teams group with the person's team runs (the control plane's executions) and their seats, a seat's session opened by its uid, read-only - Tests: vitest localRuntimeDetect (14), harnessCheck (13), sessions (14), sessionVerbs (10), each run alone; the extension-host test sessionsTreeProvider.test.ts (6, run by CI) - Docs: README (Sessions, A coding agent in your folder, the commands and settings), CHANGELOG
… scaffolding, the docs for 0.1.0 (VSCODE VS-06, VS-11, VS-14, VS-13) VS-06 `Datalayer: Start a coding agent here` (commands/startHere.ts over VS-02's LocalRuntimeService, VS-03's check, VS-05's openSessionInChat; chat/startHere.ts pure): the harness picked with its terms, the machine checked, the folder's own CLAUDE.md/AGENTS.md kept and said, a harness whose own instructions file the folder holds refused (the runtime writes it read-only), the blank harness application or one of the folder's Appspecs configured on the local runtime, the session opened and handed to the chat with the file's host terms (appHostOfSpec). VS-11 `Datalayer: Try this application` (commands/apps.ts, chat/apps.ts): `loop apps run <file> --web --watch --headless` on a free port, the page in a webview panel beside the editor, reloaded on save; Validate and Ship open the application's tabs in the browser, the uid asked once per file. VS-14 the vitest `pure` project (src/test/vitest, node) beside the webview's; the stub `loop` (src/test/fixtures/stub-loop) and the extension-host tests of both commands (src/test/sessions, src/test/apps), run by CI; the fixture workspace's CLAUDE.md and Appspecs. VS-13 README (A coding agent in your folder, Try it here), CHANGELOG and package.json at 0.1.0 — not tagged, not published: the user's pass comes first. The `yaml` dependency for the folder's Appspecs.
…r; agent-runtimes 1.5.66 The dependency raised to @datalayer/agent-runtimes ^1.5.66 (core 1.2.21, jupyter-react and jupyter-lexical 2.0.20, primer-addons 1.0.40, reactor 1.3.1): every prop the chat passes is still taken, nothing shimmed. An ask-me-first request is also an editor notification naming the application, the action and its class, never its arguments (Approve and Decline after the chat has shown it and the approval was read again, 409 and 404 said; Show focuses the chat). A diff a coding agent wrote opens in the diff view from its row (datalayer-diff: documents, the after side the file on disk when it holds what was written, its bytes and digest checked; reviewed, never applied). What it ran is written to a read-only terminal per session. The status bar says how many sessions wait or that one works; a finished turn of a session not in front is a notification. The chat draws the diff and terminal displays through a Reactor with agent-runtimes' cards; the thread's menu gains Reveal in Explorer and Open in the Studio through loop.session.action. The Sessions view opens a session in the chat (datalayer.internal.agentChat.openSession) and reads again on the chat's session-changed. CI: setup-node's npm cache dropped from the workflows (no lockfile in the repository).
…a lockfile: edgesOut of null)
…, a local session's approvals over the runtime's websocket, the terminal written as the command streams, the folder's own instructions file kept; agent-runtimes 1.5.68 - open-session: the chat on the local runtime takes the session as its thread (read by uid over the session API's AG-UI route, localSessionProtocol) and draws the thread's menu beside the header (the chat's entries and the extension's two); a deployed application's session the same on the kept runtime (AppChat openUid) - a local session's approvals (LocalApprovalSource): one websocket per local runtime (/api/v1/tool-approvals/ws, agent.snapshot / tool_approval_decision), each request said as a notification once and listed in the chat's banner (local-approvals); decided from either over the socket (local-approval-decide), the notification's decision allowed once the chat has shown it; confirmed by the next snapshot - the network bridge lets plain http/ws through to a local runtime running on this machine and to nothing else (loopbackRuntimeUrl) - the terminal written as the command streams (onToolCallUpdate -> reportToolDisplay); the Sessions view feeds datalayer.internal.sessions.attention from its reads (attentionRowsOf); the webview's Reactor started so its renderers and entries are read - Start a coding agent here no longer refuses a folder whose own instructions file is the harness's: the runtime keeps it (agent-runtimes 1.5.68, LOOP_MIN_VERSION) and the first line says where the application's go - the stub loop: 1.5.68, the approvals websocket raising one approval per session, a session described and its messages by uid; host tests src/test/sessions/surfaces.test.ts (one terminal, one diff, one approval against the stub); pure tests localApprovals (4), the loopback rule, the local session protocol, the attention rows, the kept words - prettier and cspell run on the files; the commit hook's type-aware eslint skipped (it compiles the project, which runs out of memory on this machine)
…s file is in the Python package's next release (1.5.68 carries the chat's seams only)
…ort order across the round's files, the stub loop outside eslint's projects, agent-runtimes' lib inlined for vitest and loaded for real in the extension host (its ESM imports its siblings without an extension: a resolve hook tries .js), the vscode mocks' EventEmitter, the missing SessionAttention import
…es (27, treated as errors); the VSIX smoke scripts look for the renamed extension id
…pedoc (params and returns), local-approval-decide in the chat's SurfacePost, the banner's decision returning nothing, two Markdown files formatted
…r only in case (handsFree vs HandsFree collided on macOS), and its lib/ loads under Node


A Your applications group in the Agent Chat picker lists the person's deployments (ai-agents) and talks to one that is kept always on over the runtime's session route (AG-UI), with its Tool Approvals, the editor's open file as host context when the application allows it, and tool lines under What it did. A deployment that signs its users is refused in a sentence until a route signs for the person. Pure logic in
src/chat/appChat.ts, tested (webview/test/appChat.test.ts, 18). Not yet seen in VS Code against a kept deployment.