@yottagraph-app/aether-instructions 1.1.4 → 1.1.5
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 +56 -2
- package/rules/api.mdc +41 -3
- package/rules/architecture.mdc +11 -7
- package/rules/cookbook.mdc +1 -1
package/package.json
CHANGED
package/rules/agents.mdc
CHANGED
|
@@ -175,8 +175,62 @@ Chat UI (pages/chat.vue)
|
|
|
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 chat page 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
|
|
package/rules/architecture.mdc
CHANGED
|
@@ -133,17 +133,21 @@ Tenant-specific configuration generated during provisioning. Contains GCP projec
|
|
|
133
133
|
|
|
134
134
|
## Built-in Pages
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
based on the app's needs:
|
|
136
|
+
Recent template versions include these pages. They can be kept, modified,
|
|
137
|
+
or removed based on the app's needs:
|
|
138
138
|
|
|
139
|
-
- `pages/chat.vue` -- Agent chat UI.
|
|
140
|
-
|
|
139
|
+
- `pages/chat.vue` -- Agent chat UI. Uses `useAgentChat()` and
|
|
140
|
+
`useTenantConfig()` to discover deployed agents and stream responses
|
|
141
|
+
through the Portal Gateway. Keep if the app uses AI agents.
|
|
141
142
|
- `pages/mcp.vue` -- MCP Explorer. Browse and test MCP server tools. Keep
|
|
142
143
|
if the app uses MCP servers.
|
|
143
144
|
- `pages/entity-lookup.vue` -- Entity search tool. Useful for looking up
|
|
144
145
|
NEIDs. Keep or remove based on the app.
|
|
145
146
|
|
|
146
|
-
If
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
**If these pages are missing** from your project, your project was created
|
|
148
|
+
from an older template version. Create them from scratch — they're
|
|
149
|
+
straightforward Vuetify pages. The key composables (`useAgentChat`,
|
|
150
|
+
`useTenantConfig`) are included in all template versions and provide the
|
|
151
|
+
connection logic. See the `agents` cursor rule for the gateway endpoints
|
|
152
|
+
and response formats these pages use.
|
|
149
153
|
|
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
|
}
|