@genesislcap/ai-assistant 15.34.0 → 15.35.0
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/dist/custom-elements.json +449 -0
- package/dist/dts/genesis/config.d.ts +22 -0
- package/dist/dts/genesis/config.d.ts.map +1 -0
- package/dist/dts/genesis/criteria.d.ts +83 -0
- package/dist/dts/genesis/criteria.d.ts.map +1 -0
- package/dist/dts/genesis/filter-fields.d.ts +62 -0
- package/dist/dts/genesis/filter-fields.d.ts.map +1 -0
- package/dist/dts/genesis/index.d.ts +19 -0
- package/dist/dts/genesis/index.d.ts.map +1 -0
- package/dist/dts/genesis/register-genesis-assistant.d.ts +52 -0
- package/dist/dts/genesis/register-genesis-assistant.d.ts.map +1 -0
- package/dist/dts/genesis/resource-tools.d.ts +86 -0
- package/dist/dts/genesis/resource-tools.d.ts.map +1 -0
- package/dist/dts/genesis/types.d.ts +115 -0
- package/dist/dts/genesis/types.d.ts.map +1 -0
- package/dist/esm/genesis/config.js +86 -0
- package/dist/esm/genesis/criteria.js +426 -0
- package/dist/esm/genesis/filter-fields.js +124 -0
- package/dist/esm/genesis/index.js +15 -0
- package/dist/esm/genesis/register-genesis-assistant.js +160 -0
- package/dist/esm/genesis/resource-tools.js +378 -0
- package/dist/esm/genesis/types.js +6 -0
- package/docs/genesis.md +180 -0
- package/package.json +32 -16
package/docs/genesis.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Genesis Bridge
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`@genesislcap/ai-assistant/genesis` connects the assistant to a Genesis app: it registers the
|
|
6
|
+
model providers from the platform tier table, turns the app's resources into chat tools, and
|
|
7
|
+
hands back one agent to bind to `<foundation-ai-assistant>`. It is what a generated app's mount
|
|
8
|
+
code calls; the app supplies configuration, never a model id, endpoint or key.
|
|
9
|
+
|
|
10
|
+
The API is `@beta`. This release covers **reads** — each `REQ_` resource becomes a read tool.
|
|
11
|
+
`EVENT_` resources are validated and their tool names reserved, but they are not exposed as tools
|
|
12
|
+
yet: writes need a review step in front of them and land separately.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Mounting
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { registerGenesisAssistant } from '@genesislcap/ai-assistant/genesis';
|
|
20
|
+
import config from './generated/ai-config.json';
|
|
21
|
+
import * as extensions from './extensions';
|
|
22
|
+
|
|
23
|
+
const { agents, blockedReason } = registerGenesisAssistant({ config, extensions });
|
|
24
|
+
|
|
25
|
+
const assistant = document.querySelector('foundation-ai-assistant');
|
|
26
|
+
assistant.agents = agents;
|
|
27
|
+
if (blockedReason) assistant.setBlocked(true, blockedReason);
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`registerGenesisAssistant` is synchronous and **never throws**. Anything that stops the assistant
|
|
31
|
+
from running comes back as `blockedReason` (and is logged as an error) with an empty `agents`
|
|
32
|
+
list, so a bad config or a tool-name clash costs the app its assistant, never its start-up:
|
|
33
|
+
|
|
34
|
+
- AI is switched off for the build (`feature.ai` flag) or in the config (`enabled: false`);
|
|
35
|
+
- the config is invalid (see below);
|
|
36
|
+
- an extension tool reuses a name derived from a resource — reads and writes alike, so a later
|
|
37
|
+
release that exposes writes cannot collide with a tool the app already ships;
|
|
38
|
+
- an extension tool is declared twice or has no handler;
|
|
39
|
+
- the providers cannot be registered (for example `vendors` leaves out the configured vendor).
|
|
40
|
+
|
|
41
|
+
A blocked registration registers no providers.
|
|
42
|
+
|
|
43
|
+
### Options
|
|
44
|
+
|
|
45
|
+
| Option | Default | Notes |
|
|
46
|
+
| -------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
47
|
+
| `config` | — | The app's `GenesisAiConfig`. |
|
|
48
|
+
| `container` | the DOM DI container | Where the tier providers are registered. |
|
|
49
|
+
| `endpointBase` | `<PUBLIC_PATH>/gwf/ai-service` | The app's own AI proxy; `/<vendor>/chat` is appended. A preview build passes its own. |
|
|
50
|
+
| `vendors` | `[config.vendor]` | Vendors the user may switch between. One by default: a proxy holding one key cannot answer for another vendor. |
|
|
51
|
+
| `connect` | the app's `Connect`, from DI | Resolved when a tool first runs, not at registration. |
|
|
52
|
+
| `extensions` | none | `{ toolDefinitions, toolHandlers, systemPrompt }` — the app's hand-written tools, added after the generated ones. |
|
|
53
|
+
|
|
54
|
+
The agent runs on the registry's default provider, which is the configured tier. Its system prompt
|
|
55
|
+
is the configured prompt, then a fixed rule that tool results are app data and never
|
|
56
|
+
instructions, then the extensions' prompt.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Configuration
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"enabled": true,
|
|
65
|
+
"vendor": "gemini",
|
|
66
|
+
"tier": "high",
|
|
67
|
+
"systemPrompt": "You help traders find and understand their trades.",
|
|
68
|
+
"resources": [
|
|
69
|
+
{ "name": "REQ_TRADE", "kind": "request", "context": "Trades booked in the app.", "maxRows": 200 },
|
|
70
|
+
{ "name": "EVENT_TRADE_INSERT", "kind": "event", "op": "insert", "context": "Book a trade." }
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
| Field | Rule |
|
|
76
|
+
| -------------- | ------------------------------------------------------------------------------------------- |
|
|
77
|
+
| `vendor` | A tier-table vendor. Defaults to `gemini`. |
|
|
78
|
+
| `tier` | `low`, `high` or `reasoning`. Defaults to `high`. |
|
|
79
|
+
| `name` | `REQ_<NAME>` or `EVENT_<NAME>`, unique; the tool name is the lowercased name (≤ 64 chars). |
|
|
80
|
+
| `kind` | Must match the prefix: `request` for `REQ_`, `event` for `EVENT_`. |
|
|
81
|
+
| `context` | Required. Becomes the tool description, so write it for the model. |
|
|
82
|
+
| `op` | Events only: `insert`, `modify`, `delete` or `custom`. |
|
|
83
|
+
| `maxRows` | Requests only: a whole number from 1 to 1000. Defaults to 50. |
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Read tools
|
|
88
|
+
|
|
89
|
+
A `REQ_TRADE` resource becomes the tool `req_trade` with two optional parameters:
|
|
90
|
+
|
|
91
|
+
- `filters` — a list of `{field, op, value}`, all of which must match.
|
|
92
|
+
- `max_rows` — clamped to the resource's `maxRows`; the resource default when omitted.
|
|
93
|
+
|
|
94
|
+
### Filtering is criteria, and the model never writes one
|
|
95
|
+
|
|
96
|
+
Filters become a single `CRITERIA_MATCH` expression, composed by the bridge. The model supplies
|
|
97
|
+
structure only, because criteria are parsed as Groovy on the server and the platform concatenates
|
|
98
|
+
an app's own row-level restriction into the same string (`"($userCriteria) && ($criteriaTemplate)"`).
|
|
99
|
+
A criteria string built from model output could `||` its way past that restriction. **Do not add a
|
|
100
|
+
free-text criteria parameter.**
|
|
101
|
+
|
|
102
|
+
- The fields a resource can be filtered on come from the platform's metadata reply, which is
|
|
103
|
+
fetched under the resource's **unprefixed** name (`REQ_TRADE` is read as `REQ_TRADE`, but its
|
|
104
|
+
metadata is published as `TRADE`). `CRITERIA_FIELDS` is used when the resource publishes one;
|
|
105
|
+
a request server usually does not, and its criteria are evaluated against the row, so its
|
|
106
|
+
`REPLY_FIELD`s are what can be filtered on. Types and any `VALID_VALUES` come from the same
|
|
107
|
+
reply. A resource that describes no fields gets a tool with no `filters` parameter.
|
|
108
|
+
- `op` is one of `equals`, `not_equals`, `contains`, `greater_than`, `greater_or_equal`,
|
|
109
|
+
`less_than`, `less_or_equal`, `is_blank`, `is_not_blank`. Which ones apply depends on the field's
|
|
110
|
+
type; the tool tells the model what a field holds, including an enum's values.
|
|
111
|
+
- Values are escaped and written per type — strings quoted, numbers and booleans as literals,
|
|
112
|
+
dates as `Expr.dateIs*` calls on a `yyyyMMdd` bound. The grammar and escaping match grid-pro's
|
|
113
|
+
`filter.utils.ts`, the platform's other structured-filter caller.
|
|
114
|
+
- A filter the bridge cannot build **refuses the whole read** (`error: 'invalid_filter'`) and says
|
|
115
|
+
what the resource does accept. It is never dropped silently and never sent in part: rows read
|
|
116
|
+
without a filter would answer a different question from the one the model asked.
|
|
117
|
+
|
|
118
|
+
`REQUEST` is always sent empty, so a read works the same on a `criteriaOnlyRequest` request server
|
|
119
|
+
and on one that declares request fields.
|
|
120
|
+
|
|
121
|
+
There is no paging. A request resource honours `OFFSET` only when it is declared with
|
|
122
|
+
`criteriaOnlyRequest`, which the bridge cannot see; on any other resource every "next page" is the
|
|
123
|
+
first page again, and the model would count the same rows twice. A read is one capped page, and
|
|
124
|
+
the way to the rest is a narrower read.
|
|
125
|
+
|
|
126
|
+
A read never throws. Every result carries `source: 'app-database'` and `untrusted: true`:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
// success
|
|
130
|
+
{ source, untrusted, resource, rows, truncated, note? }
|
|
131
|
+
// failure
|
|
132
|
+
{ source, untrusted, resource,
|
|
133
|
+
error: 'not_connected' | 'invalid_filter' | 'rejected' | 'request_failed', message }
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`truncated` is the server's `MORE_ROWS` when it sends one; otherwise the rule the platform's own
|
|
137
|
+
request datasource uses (an advancing `NEXT_OFFSET` or a full page means there may be more). A
|
|
138
|
+
truncated result carries a `note` telling the model these rows are not the full set, and what it
|
|
139
|
+
can do: narrow with filters when the tool has any, raise `max_rows` when it is below the cap.
|
|
140
|
+
|
|
141
|
+
`createGenesisResourceTools(resources, { connect })` builds the same tools without registering
|
|
142
|
+
anything, for an app that assembles its own agent.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Why a separate entry point
|
|
147
|
+
|
|
148
|
+
The bridge imports `@genesislcap/foundation-comms`. This package declares no `sideEffects`, so
|
|
149
|
+
everything reachable from its root ends up in every consumer's bundle — including hosts that are
|
|
150
|
+
not Genesis apps. Keeping the bridge on its own entry point keeps it out of theirs; a test walks
|
|
151
|
+
the root's import graph to hold that line.
|
|
152
|
+
|
|
153
|
+
### Why `foundation-comms` is an optional peer at `workspace:^`
|
|
154
|
+
|
|
155
|
+
`foundation-comms` is a **peer dependency** so the bridge uses the app's own `Connect`. It is
|
|
156
|
+
installed either way (`foundation-ui` depends on it); the peer is about which copy.
|
|
157
|
+
|
|
158
|
+
**What a second copy costs is silence.** A DI token is identity-based, so a second copy of comms
|
|
159
|
+
carries a different one: the bridge would resolve a `Connect` that is not the app's, the tools
|
|
160
|
+
would talk to a connection nobody logged into, and nothing anywhere would say so. There is no
|
|
161
|
+
error to catch and no symptom to grep for — only tools that answer as though the app had no data.
|
|
162
|
+
|
|
163
|
+
**Declaring beats deduping.** A regular dependency would usually be hoisted to one copy, and
|
|
164
|
+
usually is not a guarantee: it rests on the consumer's resolver flattening the tree, which a
|
|
165
|
+
version skew, a nested install or a different package manager can undo without anyone touching
|
|
166
|
+
this package. A peer states the requirement instead of hoping it is met, and the install fails
|
|
167
|
+
loudly when it is not.
|
|
168
|
+
|
|
169
|
+
It is **optional** because only `./genesis` uses it: a host that never imports the bridge should
|
|
170
|
+
not be asked to install comms.
|
|
171
|
+
|
|
172
|
+
The range is a **caret, not `workspace:*`**. `workspace:*` publishes as an exact version, and an
|
|
173
|
+
exact peer means any patch-level difference between the app's copy and this package's is an
|
|
174
|
+
ERESOLVE at install time — a hard failure over a difference that cannot matter. `workspace:^`
|
|
175
|
+
publishes as `^<version>`, which is what the requirement actually is.
|
|
176
|
+
|
|
177
|
+
Two things are new here and were chosen rather than defaulted into: this is the first
|
|
178
|
+
`workspace:^` in the monorepo, and the first internal package declared as a peer. Whatever lands
|
|
179
|
+
here is what the next package copies, which is the reason the argument is written down rather
|
|
180
|
+
than left in the `package.json` line.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genesislcap/ai-assistant",
|
|
3
3
|
"description": "Genesis AI Assistant micro-frontend",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.35.0",
|
|
5
5
|
"license": "SEE LICENSE IN license.txt",
|
|
6
6
|
"main": "dist/esm/index.js",
|
|
7
7
|
"types": "dist/ai-assistant.d.ts",
|
|
@@ -32,6 +32,10 @@
|
|
|
32
32
|
"import": "./dist/chat-driver.mjs",
|
|
33
33
|
"require": "./dist/chat-driver.cjs"
|
|
34
34
|
},
|
|
35
|
+
"./genesis": {
|
|
36
|
+
"types": "./dist/dts/genesis/index.d.ts",
|
|
37
|
+
"default": "./dist/esm/genesis/index.js"
|
|
38
|
+
},
|
|
35
39
|
"./package.json": "./package.json",
|
|
36
40
|
"./react": {
|
|
37
41
|
"types": "./dist/dts/react.d.ts",
|
|
@@ -46,6 +50,9 @@
|
|
|
46
50
|
],
|
|
47
51
|
"chat-driver": [
|
|
48
52
|
"./dist/dts/chat-driver-node.d.ts"
|
|
53
|
+
],
|
|
54
|
+
"genesis": [
|
|
55
|
+
"./dist/dts/genesis/index.d.ts"
|
|
49
56
|
]
|
|
50
57
|
}
|
|
51
58
|
},
|
|
@@ -75,29 +82,38 @@
|
|
|
75
82
|
}
|
|
76
83
|
},
|
|
77
84
|
"devDependencies": {
|
|
78
|
-
"@genesislcap/foundation-
|
|
79
|
-
"@genesislcap/
|
|
80
|
-
"@genesislcap/
|
|
81
|
-
"@genesislcap/
|
|
82
|
-
"@genesislcap/
|
|
83
|
-
"@genesislcap/
|
|
84
|
-
"@genesislcap/
|
|
85
|
+
"@genesislcap/foundation-comms": "15.35.0",
|
|
86
|
+
"@genesislcap/foundation-testing": "15.35.0",
|
|
87
|
+
"@genesislcap/genx": "15.35.0",
|
|
88
|
+
"@genesislcap/rollup-builder": "15.35.0",
|
|
89
|
+
"@genesislcap/ts-builder": "15.35.0",
|
|
90
|
+
"@genesislcap/uvu-playwright-builder": "15.35.0",
|
|
91
|
+
"@genesislcap/vite-builder": "15.35.0",
|
|
92
|
+
"@genesislcap/webpack-builder": "15.35.0",
|
|
85
93
|
"@types/dompurify": "^3.0.5",
|
|
86
94
|
"@types/marked": "^5.0.2",
|
|
87
95
|
"esbuild": "0.25.12"
|
|
88
96
|
},
|
|
89
97
|
"dependencies": {
|
|
90
|
-
"@genesislcap/foundation-ai": "15.
|
|
91
|
-
"@genesislcap/foundation-logger": "15.
|
|
92
|
-
"@genesislcap/foundation-notifications": "15.
|
|
93
|
-
"@genesislcap/foundation-redux": "15.
|
|
94
|
-
"@genesislcap/foundation-ui": "15.
|
|
95
|
-
"@genesislcap/foundation-utils": "15.
|
|
96
|
-
"@genesislcap/rapid-design-system": "15.
|
|
97
|
-
"@genesislcap/web-core": "15.
|
|
98
|
+
"@genesislcap/foundation-ai": "15.35.0",
|
|
99
|
+
"@genesislcap/foundation-logger": "15.35.0",
|
|
100
|
+
"@genesislcap/foundation-notifications": "15.35.0",
|
|
101
|
+
"@genesislcap/foundation-redux": "15.35.0",
|
|
102
|
+
"@genesislcap/foundation-ui": "15.35.0",
|
|
103
|
+
"@genesislcap/foundation-utils": "15.35.0",
|
|
104
|
+
"@genesislcap/rapid-design-system": "15.35.0",
|
|
105
|
+
"@genesislcap/web-core": "15.35.0",
|
|
98
106
|
"dompurify": "^3.3.1",
|
|
99
107
|
"marked": "^17.0.3"
|
|
100
108
|
},
|
|
109
|
+
"peerDependencies": {
|
|
110
|
+
"@genesislcap/foundation-comms": "^15.35.0"
|
|
111
|
+
},
|
|
112
|
+
"peerDependenciesMeta": {
|
|
113
|
+
"@genesislcap/foundation-comms": {
|
|
114
|
+
"optional": true
|
|
115
|
+
}
|
|
116
|
+
},
|
|
101
117
|
"repository": {
|
|
102
118
|
"type": "git",
|
|
103
119
|
"url": "git+https://github.com/genesislcap/foundation-ui.git",
|