@harperfast/template-react-ts-studio 1.11.2 → 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 +702 -490
- package/.agents/skills/harper-best-practices/SKILL.md +1 -0
- 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/delegating-to-the-built-in-agent.md +141 -0
- 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-best-practices/rules.manifest.yaml +9 -0
- 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 +702 -490
- package/agent/skills/harper-best-practices/SKILL.md +1 -0
- 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/delegating-to-the-built-in-agent.md +141 -0
- 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-best-practices/rules.manifest.yaml +9 -0
- 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
|
@@ -7,101 +7,137 @@ metadata:
|
|
|
7
7
|
mode: generate
|
|
8
8
|
sources:
|
|
9
9
|
- release-notes/v5-lincoln/v5-migration.md
|
|
10
|
-
sourceCommit:
|
|
11
|
-
inputHash:
|
|
10
|
+
sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
|
|
11
|
+
inputHash: 5ee6407370219136
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
#
|
|
14
|
+
# v5 Upgrade: Breaking Changes and Migration Guide
|
|
15
15
|
|
|
16
|
-
Instructions for the agent to
|
|
16
|
+
Instructions for the agent to apply when migrating a Harper application to v5, covering all breaking changes and required code updates.
|
|
17
17
|
|
|
18
18
|
## When to Use
|
|
19
19
|
|
|
20
|
-
Apply this rule when upgrading
|
|
20
|
+
Apply this rule when upgrading an existing Harper application to v5, when encountering runtime errors related to renamed packages, changed APIs, or security restrictions introduced in v5, or when reviewing application code for v5 compatibility before deployment.
|
|
21
21
|
|
|
22
22
|
## How It Works
|
|
23
23
|
|
|
24
|
-
1. **
|
|
24
|
+
1. **Update the package import from `harperdb` to `harper`**: All application code must import from `harper` instead of `harperdb`.
|
|
25
25
|
|
|
26
26
|
```javascript
|
|
27
27
|
import { tables } from 'harper';
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
2. **
|
|
30
|
+
2. **Enable `allowInstallScripts` if packages require install scripts**: Harper v5 uses `--ignore-scripts` by default when installing packages. If your application requires installation scripts (e.g., to install additional binaries), set the `allowInstallScripts` option when deploying.
|
|
31
31
|
|
|
32
|
-
3. **Update `Table.get` return
|
|
32
|
+
3. **Update `Table.get` usage — return value is now a frozen record object**: `Table.get` now returns a plain record object, not a table class instance. The record is frozen; you cannot mutate it directly.
|
|
33
|
+
- Replace `wasLoadedFromSource()` with `target.loadedFromSource`:
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
```javascript
|
|
36
|
+
// Old — remove this pattern:
|
|
37
|
+
const record = await Table.get(id);
|
|
38
|
+
if (record.wasLoadedFromSource()) { ... }
|
|
35
39
|
|
|
36
|
-
|
|
40
|
+
// New — use loadedFromSource on the target:
|
|
41
|
+
const target = new RequestTarget();
|
|
42
|
+
target.id = id;
|
|
43
|
+
const record = await Table.get(target);
|
|
44
|
+
if (target.loadedFromSource) {
|
|
45
|
+
// record was loaded from origin (not cache)
|
|
46
|
+
}
|
|
47
|
+
```
|
|
37
48
|
|
|
38
|
-
|
|
49
|
+
- Replace in-place mutation with object spread, since records are frozen:
|
|
39
50
|
|
|
40
|
-
|
|
51
|
+
```javascript
|
|
52
|
+
// Old — throws in v5:
|
|
53
|
+
const record = await Table.get(id);
|
|
54
|
+
record.property = 'changed';
|
|
41
55
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
- `allowedBuiltinModules` — an optional allowlist restricting which Node.js built-ins the application may import (all are allowed if omitted).
|
|
47
|
-
- `dependencyLoader` — `auto` (default), `app`, or `native`, controlling how npm dependencies are loaded through or around the VM loader.
|
|
56
|
+
// New — copy instead of mutate:
|
|
57
|
+
let record = await Table.get(id);
|
|
58
|
+
record = { ...record, property: 'changed' };
|
|
59
|
+
```
|
|
48
60
|
|
|
49
|
-
|
|
61
|
+
- `getUpdatedTime` and `getExpiresAt` methods remain available on the record object.
|
|
50
62
|
|
|
51
|
-
**
|
|
63
|
+
4. **Update transaction and context handling**: Harper v5 uses asynchronous context tracking. `Table.get` and other table calls now automatically inherit the current transaction context. Code that previously omitted context to bypass a transaction will no longer work as expected. Use `getContext` (imported from `harper`) to access and commit the current transaction explicitly when you need to see updated data.
|
|
52
64
|
|
|
53
|
-
```javascript
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
target.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
65
|
+
```javascript
|
|
66
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
67
|
+
import { getContext, transaction } from 'harper';
|
|
68
|
+
|
|
69
|
+
class MyResource {
|
|
70
|
+
static async get(target) {
|
|
71
|
+
// Commit the current transaction to read latest data:
|
|
72
|
+
await getContext().transaction.commit();
|
|
73
|
+
// Optionally wrap each poll in a new transaction:
|
|
74
|
+
while ((await transaction(() => Table.get(target))).status !== 'ready') {
|
|
75
|
+
await delay(100);
|
|
76
|
+
}
|
|
77
|
+
return Table.get(target);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
68
81
|
|
|
69
|
-
**
|
|
82
|
+
5. **Register allowed spawn commands via `allowedSpawnCommands`**: Any use of `spawn`, `exec`, or `execFile` from `node:child_process` must reference executables listed in `applications.allowedSpawnCommands` in `harperdb-config.yaml`. Provide a `name` property in the options argument to ensure only a single named process is started across threads.
|
|
70
83
|
|
|
71
|
-
|
|
72
|
-
import { setTimeout as delay } from 'node:timers/promises';
|
|
73
|
-
import { getContext, transaction } from 'harper';
|
|
74
|
-
|
|
75
|
-
class MyResource {
|
|
76
|
-
static async get(target) {
|
|
77
|
-
// The current transaction is a consistent snapshot; commit it to see updates.
|
|
78
|
-
await getContext().transaction.commit();
|
|
79
|
-
while ((await transaction(() => Table.get(target))).status !== 'ready') {
|
|
80
|
-
delay(100);
|
|
81
|
-
}
|
|
82
|
-
return Table.get(target);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
```
|
|
84
|
+
6. **Replace `blob.save()` with `saveBeforeCommit`**: The `blob.save()` method has been removed. Use the `saveBeforeCommit` flag in the options passed to the `Blob` constructor instead.
|
|
86
85
|
|
|
87
|
-
**
|
|
86
|
+
7. **Configure the `moduleLoader` and `lockdown` settings**: Harper v5 loads application modules through Node.js's VM module API. Control this behavior in `harperdb-config.yaml` under the `applications` key.
|
|
87
|
+
|
|
88
|
+
| Setting | Default | Options |
|
|
89
|
+
| ------------------ | -------------------- | --------------------------------------------------- |
|
|
90
|
+
| `moduleLoader` | `vm-current-context` | `vm-current-context`, `vm`, `native`, `compartment` |
|
|
91
|
+
| `lockdown` | `freeze-after-load` | `freeze-after-load`, `freeze`, `ses`, `none` |
|
|
92
|
+
| `dependencyLoader` | `auto` | `auto`, `app`, `native` |
|
|
93
|
+
| `allowedDirectory` | `app` | `app`, `any` |
|
|
94
|
+
- Use `moduleLoader: native` to disable the VM loader entirely and restore pre-v5 behavior (application-specific context such as tagged logging and per-app `config` will not be available).
|
|
95
|
+
- Use `lockdown: none` as a temporary workaround if a dependency modifies intrinsic prototypes at runtime and throws a `TypeError`.
|
|
96
|
+
|
|
97
|
+
## Examples
|
|
98
|
+
|
|
99
|
+
### Full `harperdb-config.yaml` `applications` block
|
|
88
100
|
|
|
89
101
|
```yaml
|
|
90
102
|
applications:
|
|
91
|
-
lockdown: freeze-after-load
|
|
92
|
-
moduleLoader: vm-current-context
|
|
93
|
-
dependencyLoader: auto
|
|
94
|
-
allowedDirectory: app
|
|
103
|
+
lockdown: freeze-after-load
|
|
104
|
+
moduleLoader: vm-current-context
|
|
105
|
+
dependencyLoader: auto
|
|
106
|
+
allowedDirectory: app
|
|
95
107
|
allowedSpawnCommands:
|
|
96
108
|
- npm
|
|
97
109
|
- node
|
|
98
|
-
# allowedBuiltinModules: [] # if omitted, all Node.js built-ins are allowed
|
|
99
110
|
```
|
|
100
111
|
|
|
101
|
-
|
|
112
|
+
### Restricting allowed built-in modules
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
applications:
|
|
116
|
+
allowedBuiltinModules:
|
|
117
|
+
- fs
|
|
118
|
+
- path
|
|
119
|
+
- http
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Disabling the VM loader for package compatibility
|
|
123
|
+
|
|
124
|
+
```yaml
|
|
125
|
+
applications:
|
|
126
|
+
moduleLoader: native
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Accessing context and committing a transaction
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
import { getContext } from 'harper';
|
|
133
|
+
|
|
134
|
+
await getContext().transaction.commit();
|
|
135
|
+
```
|
|
102
136
|
|
|
103
|
-
|
|
137
|
+
## Notes
|
|
104
138
|
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
-
|
|
139
|
+
- The `lockdown: freeze-after-load` default freezes `Object`, `Array`, `Promise`, `Map`, `Set`, and other intrinsics after all application code loads. Any code or dependency that mutates intrinsic prototypes after startup will throw a `TypeError`.
|
|
140
|
+
- Under `lockdown: ses`, the constrained `fetch` (https-only) is applied only in `vm` mode. In `vm-current-context` and `native` modes, application code uses the standard global `fetch`.
|
|
141
|
+
- In production, `allowedDirectory: app` prevents loading modules from outside the application's own directory tree. Set `allowedDirectory: any` only if your application legitimately requires it.
|
|
142
|
+
- `dependencyLoader: native` is a narrower alternative to `moduleLoader: native` — it uses native loading only for npm packages while keeping the VM loader for first-party application source files.
|
|
143
|
+
- Access Harper functions and APIs through the `harper` package rather than through global variables. Use `getContext` from `harper` to access request context without passing it explicitly through every call.
|
|
@@ -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.
|
|
@@ -422,3 +422,12 @@ rules:
|
|
|
422
422
|
- 'moduleLoader'
|
|
423
423
|
- 'lockdown'
|
|
424
424
|
- 'Table.get'
|
|
425
|
+
|
|
426
|
+
- rule: delegating-to-the-built-in-agent
|
|
427
|
+
description: How to delegate tasks to Harper's built-in agent via the CLI and the agent operations API.
|
|
428
|
+
category: ops
|
|
429
|
+
priority: 4
|
|
430
|
+
order: 8
|
|
431
|
+
mode: synthesized
|
|
432
|
+
cross_links:
|
|
433
|
+
- deploying-to-harper-fabric
|