@anchrd/intel-api 0.14.0 → 0.16.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.
Files changed (60) hide show
  1. package/dist/adapters/cloudflare/cloudflare.js +0 -68
  2. package/dist/adapters/cloudflare/cloudflare.types.d.ts +0 -39
  3. package/dist/adapters/db/db-flows.js +3 -2
  4. package/dist/adapters/db/db-grants.d.ts +1 -1
  5. package/dist/adapters/db/db-grants.js +1 -1
  6. package/dist/adapters/db/db.js +16 -113
  7. package/dist/adapters/openid/openid.js +1 -1
  8. package/dist/adapters/remote-tools/remote-tools.js +1 -1
  9. package/dist/bundle/bundle.js +31 -141
  10. package/dist/bundle/bundle.types.d.ts +1 -1
  11. package/dist/cli/cli.js +18 -11
  12. package/dist/flows/flows.d.ts +1 -1
  13. package/dist/flows/flows.js +1 -1
  14. package/dist/flows/flows.types.d.ts +4 -1
  15. package/dist/http/http.js +43 -238
  16. package/dist/http/http.types.d.ts +0 -8
  17. package/dist/indexing/indexing.js +18 -89
  18. package/dist/intel/intel.js +4 -9
  19. package/dist/intel/intel.types.d.ts +0 -6
  20. package/dist/mcp/mcp.js +84 -361
  21. package/dist/mcp/mcp.types.d.ts +2 -7
  22. package/dist/nodes/document-links/document-links.d.ts +6 -8
  23. package/dist/nodes/document-links/document-links.js +8 -31
  24. package/dist/nodes/nodes.js +24 -890
  25. package/dist/nodes/nodes.types.d.ts +14 -173
  26. package/dist/tools/tool-servers/tool-servers.d.ts +1 -1
  27. package/dist/tools/tool-servers/tool-servers.js +1 -1
  28. package/dist/tools/tools.js +37 -148
  29. package/dist/tools/tools.types.d.ts +1 -22
  30. package/migrations/0018_no_context_policy_at_last.sql +13 -6
  31. package/migrations/0019_one_name_for_the_grants.sql +52 -0
  32. package/package.json +2 -2
  33. package/dist/adapters/cloudflare-api/cloudflare-api.d.ts +0 -22
  34. package/dist/adapters/cloudflare-api/cloudflare-api.js +0 -306
  35. package/dist/adapters/cloudflare-api/cloudflare-api.types.d.ts +0 -64
  36. package/dist/adapters/cloudflare-api/cloudflare-api.types.js +0 -1
  37. package/dist/adapters/gate-applications/gate-applications.d.ts +0 -23
  38. package/dist/adapters/gate-applications/gate-applications.js +0 -88
  39. package/dist/adapters/tool-delegation/tool-delegation.d.ts +0 -22
  40. package/dist/adapters/tool-delegation/tool-delegation.js +0 -90
  41. package/dist/agent-costs/agent-costs.d.ts +0 -16
  42. package/dist/agent-costs/agent-costs.js +0 -105
  43. package/dist/agent-costs/agent-costs.types.d.ts +0 -30
  44. package/dist/agent-costs/agent-costs.types.js +0 -1
  45. package/dist/agent-runtime/agent-runtime.d.ts +0 -16
  46. package/dist/agent-runtime/agent-runtime.js +0 -150
  47. package/dist/agent-runtime/agent-runtime.types.d.ts +0 -122
  48. package/dist/agent-runtime/agent-runtime.types.js +0 -1
  49. package/dist/model-catalog/model-catalog.d.ts +0 -2
  50. package/dist/model-catalog/model-catalog.js +0 -99
  51. package/dist/model-catalog/model-catalog.types.d.ts +0 -15
  52. package/dist/model-catalog/model-catalog.types.js +0 -1
  53. package/dist/nodes/board/board.d.ts +0 -61
  54. package/dist/nodes/board/board.js +0 -826
  55. package/dist/nodes/board/board.types.d.ts +0 -38
  56. package/dist/nodes/board/board.types.js +0 -1
  57. package/migrations/0013_agents_in_the_tree.sql +0 -76
  58. package/migrations/0014_agent_applications.sql +0 -25
  59. package/migrations/0015_tools_delegated_from_a_connection.sql +0 -15
  60. package/migrations/0016_boards_in_the_tree.sql +0 -80
@@ -1,10 +1,9 @@
1
- import { ArchivedBoardStatusId, BlockNoteDocument, BlockNoteMediaType, BoardDocument, } from "@anchrd/intel-contract";
2
- import { upgradeStoredBoard } from "../nodes/board/board.js";
1
+ import { BlockNoteDocument, BlockNoteMediaType } from "@anchrd/intel-contract/node";
3
2
  export class PermanentIndexingError extends Error {
4
3
  }
5
- // The key under which a node that has exactly one vector is filed — every kind but `board`. It is
6
- // the bare node id in the index itself, which is why nothing written before anchrd/intel#301 has to
7
- // be renamed or embedded again.
4
+ // The key under which a node with exactly one vector is filed — since #390 that is every kind. It
5
+ // is the bare node id in the index itself, which is why nothing written before anchrd/intel#301 has
6
+ // to be renamed or embedded again.
8
7
  const wholeNodeChunkKey = "";
9
8
  // What the pass hands to `purgeVectors` at its end: the names it has just written, in case the node
10
9
  // was archived while it worked and the record of them was refused (anchrd/intel#348).
@@ -21,58 +20,6 @@ function indexText(mediaType, content) {
21
20
  throw new PermanentIndexingError(`Node version content is not a valid BlockNote document: ${error instanceof Error ? error.message : "unknown parse failure"}`);
22
21
  }
23
22
  }
24
- /**
25
- * One passage per task, never one per board (#285) — and since anchrd/intel#301 one VECTOR per task
26
- * too, which is what `key` carries.
27
- *
28
- * ⚠️ This is the whole reason a board is chunked at all. "Where do I stand with X" has to land on a
29
- * CARD: indexed as one blob, a board of three hundred tasks matches on any of them and answers with
30
- * whichever thousand characters the snippet function happened to cut — text from a task that may
31
- * have nothing to do with the question. Each chunk carries the task's own title, which is the
32
- * column the FTS table weights highest.
33
- *
34
- * ⚠️ The status list is not indexed, and neither is a task's own status. "Backlog" and "Done" appear
35
- * on every board in the installation, so they are the words most likely to match and the least
36
- * likely to mean anything — and in the semantic half they would drag every card of every board
37
- * towards every question phrased as a state.
38
- *
39
- * ⚠️ A task on the `archived` shelf is left out of BOTH halves (anchrd/intel#301). That shelf is
40
- * what a board has instead of deleting a card (`ArchivedBoardStatusId`), so it is the same statement
41
- * `archived_at` makes about a node one level up — and an archived node has never been searchable.
42
- * Answering "where do I stand with X" out of a card somebody swept away is the failure the ticket
43
- * names. A card in a `terminal` status is NOT swept: "we finished it" is an answer to where the work
44
- * stands, and the only thing that says a card no longer counts is the shelf.
45
- */
46
- function boardChunks(content) {
47
- let parsed;
48
- try {
49
- parsed = JSON.parse(content);
50
- }
51
- catch (error) {
52
- throw new PermanentIndexingError(`Node version content is not valid JSON: ${error instanceof Error ? error.message : "unknown parse failure"}`);
53
- }
54
- /**
55
- * ⚠️ Upgraded first, exactly like `parseStoredBoard` — this is the SECOND place a stored board
56
- * body is parsed, and it reads bodies nobody has rewritten since (anchrd/intel#318).
57
- *
58
- * `reindex` walks every current version in the installation, so an old board arrives here as it
59
- * was written: without `terminal` (#311) or with a repeated `dependsOn`. Without the upgrade the
60
- * refusal below is PERMANENT — the version is marked failed and never retried — so that board
61
- * would simply stop being findable, quietly, while its screen still worked. A rule added at one
62
- * parse site and not the other is how a fix looks complete and is not.
63
- */
64
- const board = BoardDocument.safeParse(upgradeStoredBoard(parsed));
65
- if (!board.success) {
66
- throw new PermanentIndexingError("Node version content is not a valid board document");
67
- }
68
- return board.data.tasks
69
- .filter((task) => task.status !== ArchivedBoardStatusId)
70
- .map((task) => ({
71
- key: task.id,
72
- title: task.title,
73
- text: [task.title, ...task.labels, task.description].filter(Boolean).join("\n\n"),
74
- }));
75
- }
76
23
  /**
77
24
  * What one chunk is embedded as (anchrd/intel#301).
78
25
  *
@@ -85,9 +32,9 @@ function boardChunks(content) {
85
32
  * compare against. That cost is one embedding per node, paid when that node is next saved or when
86
33
  * an administrator runs `reindex`, and never per card.
87
34
  *
88
- * ⚠️ A card is NOT prefixed with the board's title. It brings its own title as the first line of its
89
- * text already, and the board's would put a value into all three hundred fingerprints that moves
90
- * when somebody renames the board one rename, three hundred embeddings.
35
+ * ⚠️ Only the WHOLE-node chunk is prefixed, and the distinction is what kept a rename cheap while
36
+ * a node could hold many chunks: a per-chunk prefix would have put the node's title into every
37
+ * fingerprint, so renaming it once cost one embedding per chunk.
91
38
  */
92
39
  function embeddedText(target, chunk) {
93
40
  return chunk.key === wholeNodeChunkKey ? `${target.title}\n\n${chunk.text}` : chunk.text;
@@ -95,14 +42,13 @@ function embeddedText(target, chunk) {
95
42
  /**
96
43
  * The vectors this node needs, minus the ones it already has (anchrd/intel#301).
97
44
  *
98
- * ⚠️ This is the answer to "a changed card must not reindex the board". A save writes the whole
99
- * document that is what a board version IS so without this every keystroke-save of a board with
100
- * three hundred cards would cost three hundred embeddings. The fingerprint of the exact text that
101
- * was embedded is what tells an untouched card from a changed one.
45
+ * ⚠️ This is the answer to "an unchanged chunk must not be embedded again". A save writes the
46
+ * whole document, so without this every save would re-embed everything it holds. The fingerprint of
47
+ * the exact text that was embedded is what tells an untouched chunk from a changed one.
102
48
  *
103
49
  * ⚠️ The comparison is against D1 and deliberately not against Vectorize. Vectorize writes are
104
50
  * asynchronous — a vector upserted a moment ago is not readable yet — so a check made there would
105
- * answer about the save before last and re-embed a board that had just been saved twice.
51
+ * answer about the save before last and re-embed a node that had just been saved twice.
106
52
  *
107
53
  * ⚠️ The record is written only after the upsert returned, in the caller. A pass that dies in
108
54
  * between leaves the record short, so the next one embeds again; the opposite order would leave a
@@ -127,9 +73,9 @@ async function replaceVectors(deps, target, chunks) {
127
73
  const stale = stored.map((record) => record.chunkKey).filter((key) => !wanted.has(key));
128
74
  // ⚠️ The one-time sweep of the vector this node had BEFORE it was chunked. An empty record with a
129
75
  // chunked node means this is the first pass since anchrd/intel#301 (or since `reindex` emptied
130
- // the record), and the whole-board vector written under the bare node id is still sitting there —
76
+ // the record), and the whole-node vector written under the bare node id is still sitting there —
131
77
  // matching questions and answering with the wrong card's passage. Once a record exists this
132
- // branch is never taken again, so it costs one call per board rather than one per save.
78
+ // branch is never taken again, so it costs one call per node rather than one per save.
133
79
  if (stored.length === 0 && !wanted.has(wholeNodeChunkKey))
134
80
  stale.push(wholeNodeChunkKey);
135
81
  await semantic.upsert(target, changed);
@@ -207,22 +153,6 @@ export function createIndexing(deps) {
207
153
  await purgeVectors(deps, versionId);
208
154
  return;
209
155
  }
210
- // ⚠️ An agent's body is a definition, not something to read: node IDs, a cron line and a model
211
- // name (ADR-0005 §4). Indexing it verbatim would fill the index with identifiers and, worse,
212
- // put them into the passage a searcher is shown — the definition names nodes the searcher may
213
- // have no access to, and a snippet is the one place their IDs would become visible without
214
- // the tree being asked. What makes an agent findable is what a person wrote about it, so the
215
- // text is its description, and the FTS table indexes the title on its own (#139).
216
- if (target.kind === "agent") {
217
- const chunks = [
218
- { key: wholeNodeChunkKey, title: target.title, text: target.description ?? "" },
219
- ];
220
- await deps.repository.replace(target, chunks);
221
- await replaceVectors(deps, target, chunks);
222
- await purgeVectors(deps, versionId, writtenKeys(chunks));
223
- await deps.repository.markIndexed(versionId, deps.now().toISOString());
224
- return;
225
- }
226
156
  // An attachment is one object of bytes; text kinds may be several, because a table's content
227
157
  // is the join of its versions (#40). A missing segment fails the whole pass rather than
228
158
  // indexing a table with a hole in it.
@@ -240,12 +170,11 @@ export function createIndexing(deps) {
240
170
  if (text === undefined) {
241
171
  throw new PermanentIndexingError(`No document converter is configured for ${target.mediaType}`);
242
172
  }
243
- // Both halves are chunked the same way now (anchrd/intel#301): a board is one passage and
244
- // one vector per card, everything else is one of each for the node. The two indexes read the
245
- // same list, so they cannot come to disagree about what a board is made of.
246
- const chunks = target.kind === "board"
247
- ? boardChunks(text)
248
- : [{ key: wholeNodeChunkKey, title: target.title, text }];
173
+ // ⚠️ One chunk per node since #390, and the LIST is what stays. Both indexes read it, so
174
+ // they cannot come to disagree about what a node is made of which is the property that
175
+ // let a board be one passage and one vector per card (#285, anchrd/intel#301) without
176
+ // either half being told about it separately.
177
+ const chunks = [{ key: wholeNodeChunkKey, title: target.title, text }];
249
178
  await deps.repository.replace(target, chunks);
250
179
  await replaceVectors(deps, target, chunks);
251
180
  // ⚠️ Asked again, at the END of a pass that started on a live node (anchrd/intel#348). The
@@ -72,9 +72,6 @@ export function createIntel(deps) {
72
72
  flows: deps.flows,
73
73
  tools: deps.tools,
74
74
  bundle: deps.bundle,
75
- agents: deps.agents,
76
- agentCosts: deps.agentCosts,
77
- models: deps.models,
78
75
  resource,
79
76
  resourceMetadataUrl,
80
77
  ...(deps.auth ? { auth: deps.auth } : {}),
@@ -87,13 +84,11 @@ export function createIntel(deps) {
87
84
  }
88
85
  return await handleMcp(context.req.raw, {
89
86
  authorization,
90
- // ⚠️ The very token this call was authorized with, so the agent tools reach the runtime as the
91
- // caller and not as Intel. There is no cookie path on `/mcp`, so `bearer` is the same value
92
- // `authorize` just used — read again rather than passed out of it, because a function that
93
- // returned a credential beside its answer would be one somebody logs.
87
+ // ⚠️ The very token this call was authorized with, so a tool that has to speak to Gate does
88
+ // it as the caller and not as Intel. There is no cookie path on `/mcp`, so `bearer` is the
89
+ // same value `authorize` just used — read again rather than passed out of it, because a
90
+ // function that returned a credential beside its answer would be one somebody logs.
94
91
  bearer: bearer(context.req.raw.headers) ?? "",
95
- agents: deps.agents,
96
- agentCosts: deps.agentCosts,
97
92
  flows: deps.flows,
98
93
  nodes: deps.nodes,
99
94
  tools: deps.tools,
@@ -1,10 +1,7 @@
1
1
  import type { GateClient } from "@anchrd/gate-sdk";
2
- import type { AgentCostsService } from "../agent-costs/agent-costs.types.js";
3
- import type { AgentRuntimeService } from "../agent-runtime/agent-runtime.types.js";
4
2
  import type { BrowserAuth } from "../auth/auth.types.js";
5
3
  import type { BundleService } from "../bundle/bundle.types.js";
6
4
  import type { FlowService } from "../flows/flows.types.js";
7
- import type { ModelCatalogService } from "../model-catalog/model-catalog.types.js";
8
5
  import type { NodeService } from "../nodes/nodes.types.js";
9
6
  import type { ToolService } from "../tools/tools.types.js";
10
7
  export interface IntelDeps {
@@ -15,8 +12,5 @@ export interface IntelDeps {
15
12
  flows: FlowService;
16
13
  tools: ToolService;
17
14
  bundle: BundleService;
18
- agents: AgentRuntimeService;
19
- agentCosts: AgentCostsService;
20
- models: ModelCatalogService;
21
15
  auth?: BrowserAuth;
22
16
  }