@yottagraph-app/aether-instructions 1.1.28 → 1.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -225,11 +225,23 @@ Then suggest the user run `npm run dev` to preview their app locally.
225
225
 
226
226
  ---
227
227
 
228
- ## Step 8: Next Steps
228
+ ## Step 8: Deploy Agents and Next Steps
229
229
 
230
- > Your app is taking shape! Here's what you can do next:
230
+ If the app includes agents in `agents/`, offer to deploy them now:
231
+
232
+ > Your app is built! I see you have an agent in `agents/`. Want me to
233
+ > deploy it now? I can run the deployment for you.
234
+
235
+ If the user agrees (or if this is an automated build), run `/deploy_agent`
236
+ to deploy each agent. Don't just tell the user to type the command — do it
237
+ for them.
238
+
239
+ Then present next steps:
240
+
241
+ > Here's what you can do next:
231
242
  >
232
243
  > - **Preview locally** with `npm run dev`
233
244
  > - **Push to deploy** -- Vercel auto-deploys on push to main
234
- > - **Deploy an AI agent** -- run `/deploy_agent` when you have an agent ready
235
- > - **Deploy an MCP server** -- run `/deploy_mcp` for tool servers
245
+ > - **Deploy agents** -- I can deploy them for you, or use the Deploy
246
+ > button on the Broadchurch portal's project page
247
+ > - **Deploy MCP servers** -- same as above, from the portal or ask me
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yottagraph-app/aether-instructions",
3
- "version": "1.1.28",
3
+ "version": "1.1.30",
4
4
  "description": "Cursor rules, commands, and skills for Aether development",
5
5
  "files": [
6
6
  "rules",
package/rules/agents.mdc CHANGED
@@ -111,19 +111,20 @@ adk deploy agent_engine \
111
111
 
112
112
  ## How Agents Reach the App
113
113
 
114
- Once deployed, the agent is reachable through the Portal Gateway:
114
+ Once deployed, the app talks to Agent Engine directly — the portal is only
115
+ in the auth path:
115
116
 
116
117
  ```
117
- App (useAgentChat composable)
118
- POST NUXT_PUBLIC_GATEWAY_URL/api/agents/{tenantId}/{agentId}/query
119
- Portal Gateway proxies to Vertex AI Agent Engine (streamQuery)
118
+ Browser → Tenant Nitro Server (POST /api/agent/:agentId/stream)
119
+ Portal /authorize (gets short-lived tenant SA token, cached 15 min)
120
+ Agent Engine :streamQuery (direct, single hop)
120
121
  → Agent runs (may invoke tools, make multiple LLM calls)
121
- Gateway collects the ADK event stream, extracts final text
122
- → App displays it
122
+ Nitro re-emits ADK events as clean SSE to the browser
123
123
  ```
124
124
 
125
125
  The gateway URL and tenant ID come from `broadchurch.yaml` (injected as
126
- `NUXT_PUBLIC_GATEWAY_URL` and `NUXT_PUBLIC_TENANT_ORG_ID`).
126
+ `NUXT_PUBLIC_GATEWAY_URL` and `NUXT_PUBLIC_TENANT_ORG_ID`). The token is
127
+ minted for the tenant's GCP service account via SA impersonation.
127
128
 
128
129
  ### Agent Discovery
129
130
 
@@ -155,7 +156,8 @@ Each agent entry has:
155
156
  | `engine_id` | `string` | Vertex AI Agent Engine resource ID — used as `{agentId}` in query/stream URLs |
156
157
 
157
158
  The `engine_id` is the key value — it becomes the `{agentId}` path
158
- parameter in `POST /api/agents/{tenantId}/{agentId}/query`.
159
+ parameter in `/api/agent/{agentId}/stream` (the local Nitro route) and
160
+ the portal's `/authorize` endpoint.
159
161
 
160
162
  **How agents get populated:** The portal discovers agents from two sources:
161
163
  1. **Firestore** — agents registered by the deploy workflow (`deploy-agent.yml`
@@ -180,39 +182,24 @@ const agents = config.value?.agents ?? [];
180
182
  const agentId = agents[0]?.engine_id; // use as {agentId} in query URLs
181
183
  ```
182
184
 
183
- ### Gateway Request
185
+ ### Streaming via the Local Nitro Route
184
186
 
185
- ```
186
- POST {NUXT_PUBLIC_GATEWAY_URL}/api/agents/{tenantId}/{agentId}/query
187
- Content-Type: application/json
188
-
189
- { "message": "Summarize the latest 8-K filing", "session_id": "optional-session-id" }
190
- ```
187
+ The `useAgentChat` composable calls `POST /api/agent/:agentId/stream` (the
188
+ local Nitro route). This route handles token acquisition, session creation,
189
+ and SSE parsing — the browser just sees clean Server-Sent Events.
191
190
 
192
- Omit `session_id` on the first message the gateway auto-creates one.
191
+ For custom server-side agent calls (e.g. background tasks), you can call the
192
+ portal's `/authorize` endpoint directly and then use the token against
193
+ Agent Engine:
193
194
 
194
- ### Gateway Response Format
195
-
196
- ```json
197
- {
198
- "output": "The agent's final text response",
199
- "session_id": "session-abc-123",
200
- "events": [ /* raw ADK event stream */ ]
201
- }
195
+ ```typescript
196
+ const auth = await $fetch(`${gatewayUrl}/api/agents/${orgId}/${agentId}/authorize`, {
197
+ method: 'POST',
198
+ body: { user_id: 'background-task', create_session: false },
199
+ });
200
+ // auth.token, auth.engine_url, auth.expires_in
202
201
  ```
203
202
 
204
- | Field | Type | Description |
205
- |---|---|---|
206
- | `output` | `string \| any[]` | Usually the agent's final text. Falls back to the raw `events` array if the gateway couldn't extract text. |
207
- | `session_id` | `string` | Pass back on subsequent messages to continue the conversation. |
208
- | `events` | `any[]` | Full ADK event stream. Useful for debugging or building UIs that show intermediate agent steps. |
209
-
210
- **Important:** `output` is NOT always a string. When the agent's response
211
- involves complex tool chains, the gateway's server-side extraction may miss
212
- the text and return the raw events array instead. Always use
213
- `extractAgentText()` to parse `output` safely rather than treating it as a
214
- string directly.
215
-
216
203
  ### ADK Event Stream Format
217
204
 
218
205
  The `events` array contains one object per step the agent took. Each event
@@ -240,13 +227,11 @@ than objects — always handle both.
240
227
 
241
228
  ### Parsing Agent Responses (Non-Streaming)
242
229
 
243
- For one-shot calls (server routes, background tasks) where streaming isn't
244
- needed, use the buffered `/query` endpoint with `extractAgentText`:
230
+ For non-streaming use cases (e.g. extracting text from a buffered response),
231
+ use `extractAgentText`:
245
232
 
246
233
  ```typescript
247
234
  import { extractAgentText } from '~/composables/useAgentChat';
248
-
249
- const response = await $fetch(url, { method: 'POST', body: { message } });
250
235
  const text = extractAgentText(response.output);
251
236
  ```
252
237
 
@@ -255,28 +240,20 @@ JSON-string or object elements), single event objects, and several legacy
255
240
  Agent Engine response shapes. It skips `functionCall` / `functionResponse`
256
241
  events and returns the agent's final text.
257
242
 
258
- ### Streaming Responses
243
+ ### Streaming SSE Events
259
244
 
260
- The gateway also exposes a streaming endpoint that returns Server-Sent
261
- Events as the agent executes. **The `useAgentChat` composable uses this by
262
- default** — it tries `/stream` first and falls back to `/query`
245
+ The local Nitro route (`POST /api/agent/:agentId/stream`) returns
246
+ Server-Sent Events. The `useAgentChat` composable handles these
263
247
  automatically.
264
248
 
265
- ```
266
- POST {NUXT_PUBLIC_GATEWAY_URL}/api/agents/{tenantId}/{agentId}/stream
267
- Content-Type: application/json
268
-
269
- { "message": "Summarize the latest 8-K filing", "session_id": "optional" }
270
- ```
271
-
272
- The response is an SSE stream with these event types:
249
+ SSE event types:
273
250
 
274
251
  | Event | Data Shape | Description |
275
252
  |---|---|---|
276
253
  | `text` | `{ "text": "..." }` | Agent text output (replaces previous text) |
277
254
  | `function_call` | `{ "name": "...", "args": {...} }` | Agent is calling a tool |
278
255
  | `function_response` | `{ "name": "...", "response": {...} }` | Tool returned a result |
279
- | `error` | `{ "message": "..." }` | Error during processing |
256
+ | `error` | `{ "message": "...", "code": "..." }` | Error during processing (`code` is `PERMISSION_DENIED` for IAM failures) |
280
257
  | `done` | `{ "session_id": "...", "text": "..." }` | Stream complete with final text |
281
258
 
282
259
  For custom agent UIs that need streaming, import `readSSE`:
@@ -125,7 +125,21 @@ Aether apps are more than just a Nuxt SPA. The project contains three additional
125
125
 
126
126
  ### `agents/` -- ADK Agents (Python)
127
127
 
128
- Each subdirectory is a self-contained Python agent that deploys to Vertex AI Agent Engine. See the `agents` cursor rule for development patterns. Agents are deployed via the Broadchurch Portal UI or the `/deploy_agent` Cursor command, both of which trigger `deploy-agent.yml`. Once deployed, agents are reachable through the Portal Gateway (`NUXT_PUBLIC_GATEWAY_URL`). Use the `useAgentChat` composable to build a chat UI that talks to them.
128
+ Each subdirectory is a self-contained Python agent that deploys to Vertex AI Agent Engine. See the `agents` cursor rule for development patterns. Agents are deployed via the Broadchurch Portal UI or the `/deploy_agent` Cursor command, both of which trigger `deploy-agent.yml`. Use the `useAgentChat` composable to build a chat UI that talks to them.
129
+
130
+ **Agent query path:** The app talks to Agent Engine directly — the portal is
131
+ only in the auth path. The flow is:
132
+
133
+ 1. Tenant Nitro route (`server/api/agent/[agentId]/stream.post.ts`) calls the
134
+ Portal Gateway's `/authorize` endpoint to get a short-lived (15 min) GCP
135
+ access token minted for the tenant's service account.
136
+ 2. The Nitro route uses that token to call Agent Engine's `:streamQuery`
137
+ directly — streaming data does NOT flow through the portal.
138
+ 3. Tokens are cached server-side for their TTL.
139
+
140
+ If you see a 403 from Agent Engine, the tenant's service account is missing
141
+ IAM permissions (`roles/aiplatform.user`). Check the Broadchurch portal's
142
+ project detail page for IAM health status.
129
143
 
130
144
  ### `mcp-servers/` -- MCP Servers (Python)
131
145
 
@@ -140,10 +154,11 @@ Tenant-specific configuration generated during provisioning. Contains GCP projec
140
154
  The template ships composables for interacting with the Lovelace platform.
141
155
  Use these to build whatever UI fits the app:
142
156
 
143
- - **`useAgentChat()`** -- Send messages to deployed ADK agents through the
144
- Portal Gateway. Handles streaming, session management, and response
145
- parsing. See the `agents` cursor rule for gateway endpoints and response
146
- formats.
157
+ - **`useAgentChat()`** -- Send messages to deployed ADK agents. Uses the
158
+ local Nitro streaming route (`/api/agent/:agentId/stream`) which calls
159
+ Agent Engine directly with a tenant SA token. Handles streaming, session
160
+ management, and response parsing. Shows clear error messages when IAM
161
+ permissions are missing. See the `agents` cursor rule for details.
147
162
  - **`useTenantConfig()`** -- Fetch the tenant's runtime config (deployed
148
163
  agents, feature flags, MCP servers) from the Portal Gateway.
149
164
  - **`useElementalClient()`** -- When using the Elemental API from the client,
@@ -136,11 +136,23 @@ Deploy agents as needed; if the brief relies on **materialized** data, run or sc
136
136
 
137
137
  ---
138
138
 
139
- ## Step 8: Next steps
139
+ ## Step 8: Deploy Agents and Next Steps
140
140
 
141
- > Your app is taking shape. Suggested follow-ups:
141
+ If the app includes agents in `agents/`, offer to deploy them now:
142
+
143
+ > Your app is built! I see you have an agent in `agents/`. Want me to
144
+ > deploy it now? I can run the deployment for you.
145
+
146
+ If the user agrees (or if this is an automated build), run `/deploy_agent`
147
+ to deploy each agent. Don't just tell the user to type the command — do it
148
+ for them. Ensure MCP is configured for the agent runtime per `agents-data`.
149
+
150
+ Then present next steps:
151
+
152
+ > Here's what you can do next:
142
153
  >
143
154
  > - **Preview locally** with `npm run dev`
144
155
  > - **Push to deploy** — Vercel auto-deploys on push to main
145
- > - **Agents** — run `/deploy_agent` when an agent is ready; ensure MCP is configured for the agent runtime per `agents-data`
146
- > - **MCP servers** run `/deploy_mcp` if you add custom tool servers
156
+ > - **Deploy agents** — I can deploy them for you, or use the Deploy
157
+ > button on the Broadchurch portal's project page
158
+ > - **MCP servers** — same as above, from the portal or ask me