@yottagraph-app/aether-instructions 1.1.4 → 1.1.6
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/commands/build_my_app.md +3 -3
- package/package.json +1 -1
- package/rules/agents.mdc +59 -5
- package/rules/api.mdc +43 -5
- package/rules/architecture.mdc +16 -16
- package/rules/cookbook.mdc +1 -1
- package/rules/design.mdc +4 -7
package/commands/build_my_app.md
CHANGED
|
@@ -73,8 +73,8 @@ Key capabilities:
|
|
|
73
73
|
- **Query Server / Elemental API** -- the primary data source. Use `useElementalClient()` from `@yottagraph-app/elemental-api/client`. See the `api` rule.
|
|
74
74
|
- **KV storage** -- always available for preferences and lightweight data (see `pref` rule)
|
|
75
75
|
- **Supabase** -- check if `NUXT_PUBLIC_SUPABASE_URL` is in `.env` for database access
|
|
76
|
-
- **AI agent chat** -- `
|
|
77
|
-
- **MCP
|
|
76
|
+
- **AI agent chat** -- use the `useAgentChat` composable to build a chat UI for deployed agents
|
|
77
|
+
- **MCP servers** -- Lovelace MCP servers may be available (check `.cursor/mcp.json`)
|
|
78
78
|
- **Components** -- Vuetify 3 component library is available
|
|
79
79
|
|
|
80
80
|
---
|
|
@@ -96,7 +96,7 @@ Plan what you'll build:
|
|
|
96
96
|
3. What shared logic belongs in `composables/`
|
|
97
97
|
4. What data needs to be persisted (and whether KV or Supabase is appropriate)
|
|
98
98
|
5. Whether the app needs AI agents or MCP servers
|
|
99
|
-
6. Whether
|
|
99
|
+
6. Whether the app needs an agent chat page (use the `useAgentChat` composable)
|
|
100
100
|
7. Whether `app.vue` needs a sidebar, tabs, or other navigation (and what it should look like)
|
|
101
101
|
|
|
102
102
|
Present the plan to the user and ask for approval before proceeding.
|
package/package.json
CHANGED
package/rules/agents.mdc
CHANGED
|
@@ -161,22 +161,76 @@ adk deploy agent_engine \
|
|
|
161
161
|
agents/<agent-name>/
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
-
## How Agents Reach the
|
|
164
|
+
## How Agents Reach the App
|
|
165
165
|
|
|
166
166
|
Once deployed, the agent is reachable through the Portal Gateway:
|
|
167
167
|
|
|
168
168
|
```
|
|
169
|
-
|
|
169
|
+
App (useAgentChat composable)
|
|
170
170
|
→ POST NUXT_PUBLIC_GATEWAY_URL/api/agents/{tenantId}/{agentId}/query
|
|
171
171
|
→ Portal Gateway proxies to Vertex AI Agent Engine (streamQuery)
|
|
172
172
|
→ Agent runs (may invoke tools, make multiple LLM calls)
|
|
173
173
|
→ Gateway collects the ADK event stream, extracts final text
|
|
174
|
-
→
|
|
174
|
+
→ App displays it
|
|
175
175
|
```
|
|
176
176
|
|
|
177
177
|
The gateway URL and tenant ID come from `broadchurch.yaml` (injected as
|
|
178
|
-
`NUXT_PUBLIC_GATEWAY_URL` and `NUXT_PUBLIC_TENANT_ORG_ID`).
|
|
179
|
-
|
|
178
|
+
`NUXT_PUBLIC_GATEWAY_URL` and `NUXT_PUBLIC_TENANT_ORG_ID`).
|
|
179
|
+
|
|
180
|
+
### Agent Discovery
|
|
181
|
+
|
|
182
|
+
The app discovers deployed agents by fetching the tenant config:
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
GET {NUXT_PUBLIC_GATEWAY_URL}/api/config/{NUXT_PUBLIC_TENANT_ORG_ID}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The response includes an `agents` array:
|
|
189
|
+
|
|
190
|
+
```json
|
|
191
|
+
{
|
|
192
|
+
"agents": [
|
|
193
|
+
{ "name": "filing_analyst", "display_name": "Filing Analyst", "engine_id": "1234567890" },
|
|
194
|
+
{ "name": "research_bot", "display_name": "Research Bot", "engine_id": "0987654321" }
|
|
195
|
+
],
|
|
196
|
+
"features": { "chat": true, ... },
|
|
197
|
+
...
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Each agent entry has:
|
|
202
|
+
|
|
203
|
+
| Field | Type | Description |
|
|
204
|
+
|---|---|---|
|
|
205
|
+
| `name` | `string` | Agent directory name (e.g. `filing_analyst`) |
|
|
206
|
+
| `display_name` | `string` | Human-readable name for the UI |
|
|
207
|
+
| `engine_id` | `string` | Vertex AI Agent Engine resource ID — used as `{agentId}` in query/stream URLs |
|
|
208
|
+
|
|
209
|
+
The `engine_id` is the key value — it becomes the `{agentId}` path
|
|
210
|
+
parameter in `POST /api/agents/{tenantId}/{agentId}/query`.
|
|
211
|
+
|
|
212
|
+
**How agents get populated:** The portal discovers agents from two sources:
|
|
213
|
+
1. **Firestore** — agents registered by the deploy workflow (`deploy-agent.yml`
|
|
214
|
+
calls `POST /api/agents/{tenantId}` to register)
|
|
215
|
+
2. **Agent Engine API** — the portal also queries Vertex AI for reasoning
|
|
216
|
+
engines whose display name starts with the project name (e.g.
|
|
217
|
+
`my-project--filing_analyst`), catching agents that were deployed but
|
|
218
|
+
not yet registered
|
|
219
|
+
|
|
220
|
+
Both sources are merged and deduplicated by name. If the config endpoint
|
|
221
|
+
returns an empty `agents` array, no agents have been deployed yet.
|
|
222
|
+
|
|
223
|
+
Use `useTenantConfig()` to fetch this config from Vue code:
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
import { useTenantConfig } from '~/composables/useTenantConfig';
|
|
227
|
+
|
|
228
|
+
const { config, fetchConfig } = useTenantConfig();
|
|
229
|
+
await fetchConfig();
|
|
230
|
+
|
|
231
|
+
const agents = config.value?.agents ?? [];
|
|
232
|
+
const agentId = agents[0]?.engine_id; // use as {agentId} in query URLs
|
|
233
|
+
```
|
|
180
234
|
|
|
181
235
|
### Gateway Request
|
|
182
236
|
|
package/rules/api.mdc
CHANGED
|
@@ -20,7 +20,9 @@ For full endpoint documentation, read the **elemental-api skill** in
|
|
|
20
20
|
`skills/elemental-api/`. Start with `SKILL.md`, then `overview.md`.
|
|
21
21
|
These files are copied from `@yottagraph-app/elemental-api-skill` during
|
|
22
22
|
`npm install` (postinstall step) — if the directory is empty, run
|
|
23
|
-
`npm install` first.
|
|
23
|
+
`npm install` first. The skill docs contain detailed response shapes and
|
|
24
|
+
edge cases that go beyond this rule's quick reference — **run `npm install`
|
|
25
|
+
early** to make them available during initial exploration.
|
|
24
26
|
|
|
25
27
|
Key files:
|
|
26
28
|
- `entities.md` — entity search, details, and properties
|
|
@@ -153,6 +155,28 @@ const flavors = res.schema?.flavors ?? (res as any).flavors ?? [];
|
|
|
153
155
|
The `(res as any).properties` fallback is there in case the API is ever
|
|
154
156
|
fixed to match the types. Use this pattern every time.
|
|
155
157
|
|
|
158
|
+
### `getNamedEntityReport()` response is nested under `.report`
|
|
159
|
+
|
|
160
|
+
Same problem as `getSchema()`. The TypeScript types suggest entity fields
|
|
161
|
+
(`name`, `aliases`, `type`) exist at the top level. **They don't.** The
|
|
162
|
+
API wraps them in a `.report` container. The generated client does NOT
|
|
163
|
+
unwrap this automatically.
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// WRONG — name will be undefined:
|
|
167
|
+
const res = await client.getNamedEntityReport(neid);
|
|
168
|
+
const name = res.name; // undefined!
|
|
169
|
+
|
|
170
|
+
// CORRECT — always access through .report:
|
|
171
|
+
const res = await client.getNamedEntityReport(neid);
|
|
172
|
+
const name = res.report?.name ?? (res as any).name ?? neid;
|
|
173
|
+
const aliases = res.report?.aliases ?? (res as any).aliases ?? [];
|
|
174
|
+
const type = res.report?.type ?? (res as any).type;
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The `(res as any).name` fallback handles the case where the client is
|
|
178
|
+
eventually fixed to unwrap the response.
|
|
179
|
+
|
|
156
180
|
> **WARNING -- `getPropertyValues()` takes JSON-stringified arrays**: The `eids`
|
|
157
181
|
> and `pids` parameters must be JSON-encoded strings, NOT native arrays. The
|
|
158
182
|
> TypeScript type is `string`, not `string[]`. Passing a raw array will silently
|
|
@@ -175,6 +199,17 @@ financial instruments, events, and all other types are excluded — even
|
|
|
175
199
|
though the schema shows relationships like `filed` connecting organizations
|
|
176
200
|
to documents.
|
|
177
201
|
|
|
202
|
+
**Why?** The knowledge graph has two layers. The **graph layer** models
|
|
203
|
+
first-class entities (people, organizations, locations) as nodes with
|
|
204
|
+
edges between them — this is what `getLinkedEntities` traverses. The
|
|
205
|
+
**property layer** attaches everything else (documents, filings, financial
|
|
206
|
+
instruments, events) as property values on graph nodes. Documents aren't
|
|
207
|
+
"lesser" entities — they're stored differently because they're associated
|
|
208
|
+
with specific graph nodes rather than standing independently in the graph.
|
|
209
|
+
Understanding this distinction helps you generalize: if a target entity
|
|
210
|
+
type doesn't appear in the `getLinkedEntities` response, it's a property-
|
|
211
|
+
layer entity and you need `getPropertyValues` with the relationship PID.
|
|
212
|
+
|
|
178
213
|
To traverse relationships to non-graph-node types, use `getPropertyValues`
|
|
179
214
|
with the relationship PID instead. Relationship properties (`data_nindex`)
|
|
180
215
|
return linked entity IDs as values. Zero-pad the returned IDs to 20
|
|
@@ -236,9 +271,12 @@ const res = await client.getPropertyValues({
|
|
|
236
271
|
// 3. Pad IDs to 20 chars to form valid NEIDs
|
|
237
272
|
const docNeids = res.values.map((v: any) => String(v.value).padStart(20, '0'));
|
|
238
273
|
|
|
239
|
-
// 4. Get details for each linked entity
|
|
274
|
+
// 4. Get details for each linked entity (response is nested under .report)
|
|
240
275
|
const reports = await Promise.all(
|
|
241
|
-
docNeids.map((neid: string) =>
|
|
276
|
+
docNeids.map(async (neid: string) => {
|
|
277
|
+
const r = await client.getNamedEntityReport(neid);
|
|
278
|
+
return r.report ?? r;
|
|
279
|
+
}),
|
|
242
280
|
);
|
|
243
281
|
```
|
|
244
282
|
|
|
@@ -291,8 +329,8 @@ the servers route through the Portal Gateway proxy (no credentials needed).
|
|
|
291
329
|
For local development without a gateway, the servers require an
|
|
292
330
|
`AUTH0_M2M_DEV_TOKEN` environment variable.
|
|
293
331
|
|
|
294
|
-
|
|
295
|
-
|
|
332
|
+
These servers are also accessible from the browser through the Portal
|
|
333
|
+
Gateway, so you can build MCP tool exploration UIs if needed.
|
|
296
334
|
|
|
297
335
|
### When MCP Servers Are Available
|
|
298
336
|
|
package/rules/architecture.mdc
CHANGED
|
@@ -121,7 +121,7 @@ Aether apps are more than just a Nuxt SPA. The project contains three additional
|
|
|
121
121
|
|
|
122
122
|
### `agents/` -- ADK Agents (Python)
|
|
123
123
|
|
|
124
|
-
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,
|
|
124
|
+
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.
|
|
125
125
|
|
|
126
126
|
### `mcp-servers/` -- MCP Servers (Python)
|
|
127
127
|
|
|
@@ -131,19 +131,19 @@ Each subdirectory is a FastMCP server that deploys to Cloud Run. See the `mcp-se
|
|
|
131
131
|
|
|
132
132
|
Tenant-specific configuration generated during provisioning. Contains GCP project, org ID, service account, gateway URL, and query server URL. Read by deploy commands and GitHub Actions workflows. Don't edit manually.
|
|
133
133
|
|
|
134
|
-
##
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
134
|
+
## Available Composables for Platform Features
|
|
135
|
+
|
|
136
|
+
The template ships composables for interacting with the Lovelace platform.
|
|
137
|
+
Use these to build whatever UI fits the app:
|
|
138
|
+
|
|
139
|
+
- **`useAgentChat()`** -- Send messages to deployed ADK agents through the
|
|
140
|
+
Portal Gateway. Handles streaming, session management, and response
|
|
141
|
+
parsing. See the `agents` cursor rule for gateway endpoints and response
|
|
142
|
+
formats.
|
|
143
|
+
- **`useTenantConfig()`** -- Fetch the tenant's runtime config (deployed
|
|
144
|
+
agents, feature flags, MCP servers) from the Portal Gateway.
|
|
145
|
+
- **`useElementalClient()`** -- Query Server client for entities, news,
|
|
146
|
+
filings, etc. See the `api` rule.
|
|
147
|
+
- **`usePrefsStore()` / `Pref<T>`** -- KV-backed user preferences. See
|
|
148
|
+
the `pref` rule.
|
|
149
149
|
|
package/rules/cookbook.mdc
CHANGED
|
@@ -467,7 +467,7 @@ NOT supported — use `getPropertyValues` with the relationship PID instead.
|
|
|
467
467
|
docNeids.map(async (neid: string) => {
|
|
468
468
|
try {
|
|
469
469
|
const r = await client.getNamedEntityReport(neid);
|
|
470
|
-
return r.name
|
|
470
|
+
return r.report?.name ?? (r as any).name ?? neid;
|
|
471
471
|
} catch {
|
|
472
472
|
return neid;
|
|
473
473
|
}
|
package/rules/design.mdc
CHANGED
|
@@ -15,16 +15,13 @@ The sections of the design doc are flexible and you should add or remove section
|
|
|
15
15
|
|
|
16
16
|
# Starter App is a Placeholder
|
|
17
17
|
|
|
18
|
-
The default UI that ships with this template
|
|
19
|
-
|
|
20
|
-
building from a project brief or user request, feel free to:
|
|
18
|
+
The default UI that ships with this template is **placeholder content**.
|
|
19
|
+
When building from a project brief or user request, feel free to:
|
|
21
20
|
|
|
22
21
|
- **Replace** `pages/index.vue` with the app's real home page
|
|
23
|
-
- **Remove**
|
|
24
|
-
if the app doesn't need them
|
|
22
|
+
- **Remove** any pages that don't fit the app
|
|
25
23
|
- **Restructure** the navigation, layout, and branding entirely
|
|
26
|
-
- **Keep**
|
|
27
|
-
`agents/`, and `pages/chat.vue` (if the app uses agent chat)
|
|
24
|
+
- **Keep** the infrastructure: `composables/`, `server/api/kv/`, `agents/`
|
|
28
25
|
|
|
29
26
|
Do NOT treat the existing UI as something to preserve. Build what the
|
|
30
27
|
user described, using the template's infrastructure and patterns but not
|