@harperfast/template-react-ts-studio 1.11.3 → 1.11.4
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/.agents/skills/harper-best-practices/AGENTS.md +567 -490
- package/.agents/skills/harper-best-practices/rules/automatic-apis.md +46 -78
- package/.agents/skills/harper-best-practices/rules/defining-relationships.md +41 -63
- package/.agents/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +59 -45
- package/.agents/skills/harper-best-practices/rules/load-env.md +24 -23
- package/.agents/skills/harper-best-practices/rules/programmatic-table-requests.md +62 -78
- package/.agents/skills/harper-best-practices/rules/querying-rest-apis.md +92 -65
- package/.agents/skills/harper-best-practices/rules/schema-design-tooling.md +53 -55
- package/.agents/skills/harper-best-practices/rules/v5-upgrade.md +98 -62
- package/.agents/skills/harper-best-practices/rules/vector-indexing.md +113 -42
- package/.agents/skills/harper-mcp/AGENTS.md +501 -0
- package/.agents/skills/harper-mcp/SKILL.md +91 -0
- package/.agents/skills/harper-mcp/rules/automatic-verb-tools.md +50 -0
- package/.agents/skills/harper-mcp/rules/connecting-clients.md +59 -0
- package/.agents/skills/harper-mcp/rules/custom-mcp-prompts.md +52 -0
- package/.agents/skills/harper-mcp/rules/custom-mcp-resources.md +64 -0
- package/.agents/skills/harper-mcp/rules/custom-mcp-tools.md +72 -0
- package/.agents/skills/harper-mcp/rules/durable-quotas.md +73 -0
- package/.agents/skills/harper-mcp/rules/enabling-mcp.md +63 -0
- package/.agents/skills/harper-mcp/rules/rate-limiting.md +62 -0
- package/.agents/skills/harper-mcp/rules/resources-surface.md +44 -0
- package/.agents/skills/harper-mcp/rules/security-posture.md +36 -0
- package/.agents/skills/harper-mcp/rules.manifest.yaml +203 -0
- package/agent/skills/harper-best-practices/AGENTS.md +567 -490
- package/agent/skills/harper-best-practices/rules/automatic-apis.md +46 -78
- package/agent/skills/harper-best-practices/rules/defining-relationships.md +41 -63
- package/agent/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +59 -45
- package/agent/skills/harper-best-practices/rules/load-env.md +24 -23
- package/agent/skills/harper-best-practices/rules/programmatic-table-requests.md +62 -78
- package/agent/skills/harper-best-practices/rules/querying-rest-apis.md +92 -65
- package/agent/skills/harper-best-practices/rules/schema-design-tooling.md +53 -55
- package/agent/skills/harper-best-practices/rules/v5-upgrade.md +98 -62
- package/agent/skills/harper-best-practices/rules/vector-indexing.md +113 -42
- package/agent/skills/harper-mcp/AGENTS.md +501 -0
- package/agent/skills/harper-mcp/SKILL.md +83 -0
- package/agent/skills/harper-mcp/rules/automatic-verb-tools.md +50 -0
- package/agent/skills/harper-mcp/rules/connecting-clients.md +59 -0
- package/agent/skills/harper-mcp/rules/custom-mcp-prompts.md +52 -0
- package/agent/skills/harper-mcp/rules/custom-mcp-resources.md +64 -0
- package/agent/skills/harper-mcp/rules/custom-mcp-tools.md +72 -0
- package/agent/skills/harper-mcp/rules/durable-quotas.md +73 -0
- package/agent/skills/harper-mcp/rules/enabling-mcp.md +63 -0
- package/agent/skills/harper-mcp/rules/rate-limiting.md +62 -0
- package/agent/skills/harper-mcp/rules/resources-surface.md +44 -0
- package/agent/skills/harper-mcp/rules/security-posture.md +36 -0
- package/agent/skills/harper-mcp/rules.manifest.yaml +203 -0
- package/package.json +1 -1
- package/skills-lock.json +7 -1
|
@@ -5,8 +5,8 @@ metadata:
|
|
|
5
5
|
mode: generate
|
|
6
6
|
sources:
|
|
7
7
|
- reference/v5/database/schema.md#Vector Indexing
|
|
8
|
-
sourceCommit:
|
|
9
|
-
inputHash:
|
|
8
|
+
sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
|
|
9
|
+
inputHash: 225b9bea420d9adc
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Vector Indexing
|
|
@@ -15,11 +15,11 @@ Instructions for the agent to enable HNSW vector indexes on table fields and que
|
|
|
15
15
|
|
|
16
16
|
## When to Use
|
|
17
17
|
|
|
18
|
-
Apply this rule when adding a vector similarity search capability to a Harper table — for example, storing text embeddings and querying for nearest neighbors, filtering by distance threshold, or
|
|
18
|
+
Apply this rule when adding a vector similarity search capability to a Harper table — for example, storing text embeddings and querying for nearest neighbors, filtering by distance threshold, or combining vector search with record-level access control. See [adding-tables-with-schemas.md](adding-tables-with-schemas.md) for how to define the surrounding table schema.
|
|
19
19
|
|
|
20
20
|
## How It Works
|
|
21
21
|
|
|
22
|
-
1. **Declare the vector index on a
|
|
22
|
+
1. **Declare the vector index** on a `[Float]` field using `@indexed(type: "HNSW")`:
|
|
23
23
|
|
|
24
24
|
```graphql
|
|
25
25
|
type Document @table {
|
|
@@ -28,7 +28,7 @@ Apply this rule when adding a vector similarity search capability to a Harper ta
|
|
|
28
28
|
}
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
2. **Query
|
|
31
|
+
2. **Query nearest neighbors** using the `sort` parameter with `attribute` and `target`:
|
|
32
32
|
|
|
33
33
|
```javascript
|
|
34
34
|
let results = Document.search({
|
|
@@ -37,7 +37,7 @@ Apply this rule when adding a vector similarity search capability to a Harper ta
|
|
|
37
37
|
});
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
3. **Combine with filter conditions
|
|
40
|
+
3. **Combine with filter conditions** to narrow results before or during traversal:
|
|
41
41
|
|
|
42
42
|
```javascript
|
|
43
43
|
let results = Document.search({
|
|
@@ -47,7 +47,25 @@ Apply this rule when adding a vector similarity search capability to a Harper ta
|
|
|
47
47
|
});
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
Conditions are evaluated _during_ graph traversal (predicate-aware search), not after. Very selective conditions are automatically diverted to an exact-scan strategy.
|
|
51
|
+
|
|
52
|
+
4. **Use a `vectorFilter` function** for predicates not expressible as conditions (JavaScript API only):
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
let results = Document.search(
|
|
56
|
+
{
|
|
57
|
+
sort: { attribute: 'textEmbeddings', target: searchVector },
|
|
58
|
+
vectorFilter: (record) =>
|
|
59
|
+
record.tenantId === context.user.tenantId && record.status === 'published',
|
|
60
|
+
limit: 10,
|
|
61
|
+
},
|
|
62
|
+
context,
|
|
63
|
+
);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The function receives a frozen candidate record and must return a boolean synchronously. It must be side-effect free and fast — it can run once per candidate visited during traversal (verdicts are memoized per query).
|
|
67
|
+
|
|
68
|
+
5. **Filter by distance threshold** using `target` on a condition instead of `sort`:
|
|
51
69
|
|
|
52
70
|
```javascript
|
|
53
71
|
let results = Document.search({
|
|
@@ -60,7 +78,7 @@ Apply this rule when adding a vector similarity search capability to a Harper ta
|
|
|
60
78
|
});
|
|
61
79
|
```
|
|
62
80
|
|
|
63
|
-
|
|
81
|
+
6. **Include computed distance in results** using the `$distance` field in `select`:
|
|
64
82
|
|
|
65
83
|
```javascript
|
|
66
84
|
let results = Document.search({
|
|
@@ -70,7 +88,9 @@ Apply this rule when adding a vector similarity search capability to a Harper ta
|
|
|
70
88
|
});
|
|
71
89
|
```
|
|
72
90
|
|
|
73
|
-
|
|
91
|
+
`$distance` works in both `sort`-based and threshold-based queries.
|
|
92
|
+
|
|
93
|
+
7. **Override the distance function or exploration budget per query** via options on the `sort` descriptor:
|
|
74
94
|
|
|
75
95
|
```javascript
|
|
76
96
|
let results = Document.search({
|
|
@@ -79,31 +99,76 @@ Apply this rule when adding a vector similarity search capability to a Harper ta
|
|
|
79
99
|
});
|
|
80
100
|
```
|
|
81
101
|
|
|
82
|
-
- `distance` —
|
|
83
|
-
- `ef` — overrides the search exploration budget. Higher values improve recall at the cost of latency.
|
|
102
|
+
- `distance` — `"cosine"`, `"euclidean"`, or `"dotProduct"`.
|
|
103
|
+
- `ef` — overrides the search exploration budget for this query. Higher values improve recall at the cost of latency.
|
|
84
104
|
|
|
85
|
-
|
|
105
|
+
8. **Tune filtered traversal** when a `vectorFilter` is very selective by raising `ef` or `filterExpansion`:
|
|
86
106
|
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
107
|
+
```javascript
|
|
108
|
+
let results = Document.search(
|
|
109
|
+
{
|
|
110
|
+
sort: { attribute: 'textEmbeddings', target: searchVector, ef: 200, filterExpansion: 40 },
|
|
111
|
+
vectorFilter: (record) => record.category === 'rare',
|
|
112
|
+
limit: 10,
|
|
113
|
+
},
|
|
114
|
+
context,
|
|
115
|
+
);
|
|
93
116
|
```
|
|
94
117
|
|
|
95
|
-
|
|
118
|
+
Filtered traversal visits at most `ef * filterExpansion` nodes (`filterExpansion` defaults to `24`). If the budget is exhausted before results fill, the search returns what was found rather than erroring.
|
|
119
|
+
|
|
120
|
+
9. **Configure HNSW index parameters** directly on the directive:
|
|
96
121
|
|
|
97
122
|
```graphql
|
|
98
123
|
type Document @table {
|
|
99
124
|
id: Long @primaryKey
|
|
100
|
-
textEmbeddings: [Float]
|
|
125
|
+
textEmbeddings: [Float]
|
|
126
|
+
@indexed(type: "HNSW", distance: "euclidean", optimizeRouting: 0, efConstructionSearch: 100)
|
|
101
127
|
}
|
|
102
128
|
```
|
|
103
129
|
|
|
130
|
+
| Parameter | Default | Description |
|
|
131
|
+
| ---------------------- | ----------------- | ------------------------------------------------------------------------------------------------ |
|
|
132
|
+
| `distance` | `"cosine"` | Distance function: `"cosine"`, `"euclidean"`, or `"dotProduct"` |
|
|
133
|
+
| `efConstruction` | `100` | Max nodes explored during index construction. Higher = better recall, lower = better performance |
|
|
134
|
+
| `M` | `16` | Preferred connections per graph layer |
|
|
135
|
+
| `optimizeRouting` | `0.5` | Heuristic aggressiveness for omitting redundant connections (0 = off, 1 = most aggressive) |
|
|
136
|
+
| `mL` | computed from `M` | Normalization factor for level generation |
|
|
137
|
+
| `efConstructionSearch` | auto-scaled | Max nodes explored during search. When unset, auto-scales with index size |
|
|
138
|
+
| `quantization` | — | `"int8"` stores vectors quantized to int8 |
|
|
139
|
+
| `filterExpansion` | `24` | Visit-budget multiplier for filtered search |
|
|
140
|
+
|
|
141
|
+
Changing `efConstructionSearch` on an existing index does not trigger a rebuild. Changing structural parameters (`distance`, `M`, `efConstruction`, `quantization`) does rebuild the index.
|
|
142
|
+
|
|
143
|
+
10. **Enable int8 quantization** to reduce index size and memory usage:
|
|
144
|
+
|
|
145
|
+
```graphql
|
|
146
|
+
type Document @table {
|
|
147
|
+
id: Long @primaryKey
|
|
148
|
+
textEmbeddings: [Float] @indexed(type: "HNSW", quantization: "int8")
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Graph navigation uses quantized distances. For `sort` queries, Harper re-ranks results against full-precision vectors, restoring exact ordering and exact `$distance` values. Distance-threshold queries filter on the approximate distance.
|
|
153
|
+
|
|
154
|
+
11. **Implement record-level access control** by overriding `allowRead(user, target, context)` on the table resource. During vector queries the check participates in graph traversal, so a restricted user receives the k nearest records they are allowed to see:
|
|
155
|
+
|
|
156
|
+
```javascript
|
|
157
|
+
export class Reports extends tables.Reports {
|
|
158
|
+
allowRead(user, target, context) {
|
|
159
|
+
if (!super.allowRead(user, target, context)) return false;
|
|
160
|
+
if (user.role.permission.super_user) return true;
|
|
161
|
+
if (this.ownerId == null) return true;
|
|
162
|
+
return this.ownerId === user.id;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The check must be synchronous, side-effect free, and fast. `this` is the frozen record during per-record evaluation. A thrown exception denies that record (fail closed).
|
|
168
|
+
|
|
104
169
|
## Examples
|
|
105
170
|
|
|
106
|
-
Full schema with custom HNSW parameters
|
|
171
|
+
**Full schema with custom HNSW parameters:**
|
|
107
172
|
|
|
108
173
|
```graphql
|
|
109
174
|
type Document @table {
|
|
@@ -113,16 +178,33 @@ type Document @table {
|
|
|
113
178
|
}
|
|
114
179
|
```
|
|
115
180
|
|
|
181
|
+
**Nearest-neighbor search with distance output:**
|
|
182
|
+
|
|
116
183
|
```javascript
|
|
117
|
-
// Nearest-neighbor search with distance scores
|
|
118
184
|
let results = Document.search({
|
|
119
185
|
select: ['name', '$distance'],
|
|
120
186
|
sort: { attribute: 'textEmbeddings', target: searchVector },
|
|
121
187
|
limit: 5,
|
|
122
188
|
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Filtered vector search with tuned traversal budget:**
|
|
123
192
|
|
|
124
|
-
|
|
125
|
-
let
|
|
193
|
+
```javascript
|
|
194
|
+
let results = Document.search(
|
|
195
|
+
{
|
|
196
|
+
sort: { attribute: 'textEmbeddings', target: searchVector, ef: 200, filterExpansion: 40 },
|
|
197
|
+
vectorFilter: (record) => record.category === 'rare',
|
|
198
|
+
limit: 10,
|
|
199
|
+
},
|
|
200
|
+
context,
|
|
201
|
+
);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Distance threshold query (no ranking, cutoff only):**
|
|
205
|
+
|
|
206
|
+
```javascript
|
|
207
|
+
let results = Document.search({
|
|
126
208
|
conditions: {
|
|
127
209
|
attribute: 'textEmbeddings',
|
|
128
210
|
comparator: 'lt',
|
|
@@ -134,21 +216,10 @@ let closeMatches = Document.search({
|
|
|
134
216
|
|
|
135
217
|
## Notes
|
|
136
218
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
| `optimizeRouting` | `0.5` | Heuristic aggressiveness for omitting redundant connections (0 = off, 1 = most aggressive) |
|
|
145
|
-
| `mL` | computed from `M` | Normalization factor for level generation |
|
|
146
|
-
| `efConstructionSearch` | auto-scaled | Max nodes explored during search. When unset, auto-scales with index size; setting it fixes the budget |
|
|
147
|
-
| `quantization` | — | `"int8"` stores vectors quantized to int8 |
|
|
148
|
-
|
|
149
|
-
- The `distance` option on a per-query `sort` descriptor accepts `"cosine"`, `"euclidean"`, or `"dotProduct"`.
|
|
150
|
-
- When no `ef` is passed and `efConstructionSearch` (or `efConstruction`) is not explicitly set on the index, the search budget auto-scales with index size.
|
|
151
|
-
- `efConstruction` seeds the initial value of `efConstructionSearch`; setting either one fixes the search budget.
|
|
152
|
-
- The correct parameter name is `efConstructionSearch` (not `efSearchConstruction`).
|
|
153
|
-
- `$distance` is available in both `sort`-based ranking and `conditions`-based threshold queries.
|
|
154
|
-
- For `quantization: "int8"`, distance-threshold (`lt`/`le`) queries filter on approximate distance; `sort` queries re-rank against full-precision vectors.
|
|
219
|
+
- Use `@indexed(type: "HNSW")` on a `[Float]` field — not on scalar fields.
|
|
220
|
+
- The default `distance` is `"cosine"`. Override it per-index via the directive or per-query via the `sort` descriptor.
|
|
221
|
+
- `efConstruction` seeds the initial value of `efConstructionSearch`. When neither is set, the search budget auto-scales with index size.
|
|
222
|
+
- `vectorFilter` is available from the JavaScript API only; it cannot be expressed in a REST query string.
|
|
223
|
+
- The parameter name Harper reads is `efConstructionSearch` (not `efSearchConstruction`).
|
|
224
|
+
- `$distance` must be listed explicitly in `select` to appear in results.
|
|
225
|
+
- For record-level `allowRead` overrides: collection-scope calls (where `this.ownerId` is `null`) should return `true` to open the connection; per-record filtering happens during query execution and event delivery.
|