@yottagraph-app/aether-instructions 1.1.28 → 1.1.29
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.
- package/package.json +1 -1
- package/rules/agents.mdc +30 -53
- package/rules/architecture.mdc +20 -5
package/package.json
CHANGED
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
|
|
114
|
+
Once deployed, the app talks to Agent Engine directly — the portal is only
|
|
115
|
+
in the auth path:
|
|
115
116
|
|
|
116
117
|
```
|
|
117
|
-
|
|
118
|
-
→
|
|
119
|
-
→
|
|
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
|
-
→
|
|
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
|
|
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
|
-
###
|
|
185
|
+
### Streaming via the Local Nitro Route
|
|
184
186
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
{
|
|
198
|
-
|
|
199
|
-
|
|
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
|
|
244
|
-
|
|
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
|
|
243
|
+
### Streaming SSE Events
|
|
259
244
|
|
|
260
|
-
The
|
|
261
|
-
Events
|
|
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`:
|
package/rules/architecture.mdc
CHANGED
|
@@ -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`.
|
|
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
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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,
|