@anchrd/intel-api 0.6.6 → 0.7.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/README.md +44 -3
- package/dist/adapters/cloudflare/cloudflare.js +50 -16
- package/dist/adapters/cloudflare/cloudflare.types.d.ts +11 -0
- package/dist/adapters/content/content.d.ts +1 -1
- package/dist/adapters/db/db-flows.js +161 -20
- package/dist/adapters/db/db-grants.d.ts +13 -2
- package/dist/adapters/db/db-grants.js +25 -8
- package/dist/adapters/db/db-indexing.d.ts +2 -2
- package/dist/adapters/db/db-indexing.js +26 -19
- package/dist/adapters/db/db.d.ts +3 -3
- package/dist/adapters/db/db.js +448 -119
- package/dist/adapters/gate-applications/gate-applications.d.ts +23 -0
- package/dist/adapters/gate-applications/gate-applications.js +66 -0
- package/dist/adapters/index-queue/index-queue.d.ts +1 -1
- package/dist/adapters/index-queue/index-queue.js +2 -2
- package/dist/adapters/semantic-index/semantic-index.types.d.ts +2 -2
- package/dist/agent-runtime/agent-runtime.d.ts +16 -0
- package/dist/agent-runtime/agent-runtime.js +76 -0
- package/dist/agent-runtime/agent-runtime.types.d.ts +57 -0
- package/dist/bundle/bundle.d.ts +4 -0
- package/dist/bundle/bundle.js +1035 -0
- package/dist/bundle/bundle.types.d.ts +33 -0
- package/dist/bundle/bundle.types.js +1 -0
- package/dist/cli/cli.js +10 -1
- package/dist/flows/flows.d.ts +8 -8
- package/dist/flows/flows.js +158 -42
- package/dist/flows/flows.types.d.ts +40 -7
- package/dist/http/http.d.ts +1 -0
- package/dist/http/http.js +329 -63
- package/dist/http/http.types.d.ts +6 -2
- package/dist/indexing/indexing.js +14 -2
- package/dist/indexing/indexing.types.d.ts +2 -2
- package/dist/intel/intel.js +12 -3
- package/dist/intel/intel.types.d.ts +6 -2
- package/dist/mcp/mcp.js +483 -124
- package/dist/mcp/mcp.types.d.ts +11 -2
- package/dist/nodes/nodes.d.ts +2 -0
- package/dist/nodes/nodes.js +1337 -0
- package/dist/nodes/nodes.types.d.ts +314 -0
- package/dist/nodes/nodes.types.js +1 -0
- package/migrations/0011_one_name_for_the_tree.sql +53 -0
- package/migrations/0012_table_snapshots.sql +29 -0
- package/migrations/0013_agents_in_the_tree.sql +76 -0
- package/migrations/0014_agent_applications.sql +25 -0
- package/package.json +3 -2
- package/dist/knowledge/knowledge.d.ts +0 -2
- package/dist/knowledge/knowledge.js +0 -761
- package/dist/knowledge/knowledge.types.d.ts +0 -198
- /package/dist/{knowledge/knowledge.types.js → agent-runtime/agent-runtime.types.js} +0 -0
- /package/dist/{knowledge → nodes}/document-links/document-links.d.ts +0 -0
- /package/dist/{knowledge → nodes}/document-links/document-links.js +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AgentApplications } from "../../nodes/nodes.types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Intel's door to Gate's Applications surface (`anchrd/gate#223`/`#224`, Gate 0.10.x).
|
|
4
|
+
*
|
|
5
|
+
* ⚠️ This is the one Gate call Intel makes with the CALLER's bearer instead of its service key, and
|
|
6
|
+
* that is not a shortcut — the service key does not open this door. A Gate service key authorizes
|
|
7
|
+
* `/api/v1/authorization` and `/api/v1/schema` and nothing else (Gate's two-token rule); the
|
|
8
|
+
* Applications routes are admin-gated and resolve a real principal, so the person creating an agent
|
|
9
|
+
* needs `applications:write` in Gate and their act is audited in Gate under their own name. A
|
|
10
|
+
* service key here would have made Intel the author of every machine principal an installation ever
|
|
11
|
+
* grew, which is the opposite of what an audit trail is for.
|
|
12
|
+
*
|
|
13
|
+
* ⚠️ Nothing this module receives from Gate is logged, wrapped into a message, or returned other
|
|
14
|
+
* than through the one typed answer below. `create` is handed a plain-text key, and the shortest
|
|
15
|
+
* path from here to a leak is an error that quotes the response body — so no refusal names anything
|
|
16
|
+
* but the status Gate answered with.
|
|
17
|
+
*/
|
|
18
|
+
export interface GateApplicationsDeps {
|
|
19
|
+
fetch: (url: string, init?: RequestInit) => Promise<Response>;
|
|
20
|
+
gateUrl: string;
|
|
21
|
+
timeoutMs?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function createGateApplications(deps: GateApplicationsDeps): AgentApplications;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { IntelError } from "../../shared/intel-error/intel-error.js";
|
|
3
|
+
// Tolerant on purpose, unlike Intel's own contracts: this is somebody else's wire format, and a
|
|
4
|
+
// field Gate adds tomorrow must not stop an installation from creating an agent. Only what Intel
|
|
5
|
+
// actually reads is named.
|
|
6
|
+
const CreatedApplication = z.object({ id: z.string().min(1), key: z.string().min(1) });
|
|
7
|
+
const DefaultTimeoutMs = 10_000;
|
|
8
|
+
export function createGateApplications(deps) {
|
|
9
|
+
const base = deps.gateUrl.replace(/\/+$/, "");
|
|
10
|
+
const timeoutMs = deps.timeoutMs ?? DefaultTimeoutMs;
|
|
11
|
+
// Gate's refusals, translated once. A 401/403 is the caller's missing `applications:write` and is
|
|
12
|
+
// permanent until somebody acts in Gate, so it is answered as a refusal rather than as an outage;
|
|
13
|
+
// everything else — a 5xx, a timeout, a DNS failure — is "Gate did not answer", and the caller is
|
|
14
|
+
// told that no agent was created rather than left to guess.
|
|
15
|
+
function refusal(status) {
|
|
16
|
+
if (status === 401 || status === 403) {
|
|
17
|
+
return new IntelError(403, "agent_application_forbidden", "Gate refused this account the management of applications — creating an agent needs the applications permission in Gate");
|
|
18
|
+
}
|
|
19
|
+
return new IntelError(502, "agent_application_unavailable", `Gate could not manage this agent's application (${status})`);
|
|
20
|
+
}
|
|
21
|
+
async function call(path, token, body) {
|
|
22
|
+
try {
|
|
23
|
+
return await deps.fetch(`${base}/api/v1/applications${path}`, {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: {
|
|
26
|
+
"content-type": "application/json",
|
|
27
|
+
authorization: `Bearer ${token}`,
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify(body),
|
|
30
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// ⚠️ The caught error is dropped rather than described. A fetch failure carries the URL, and
|
|
35
|
+
// the URL is the one place the bearer could still be if a caller ever put it in a query.
|
|
36
|
+
throw new IntelError(502, "agent_application_unavailable", "Gate did not answer, so no agent application was created or changed");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
async create(input) {
|
|
41
|
+
const response = await call("", input.token, { name: input.name });
|
|
42
|
+
if (!response.ok)
|
|
43
|
+
throw refusal(response.status);
|
|
44
|
+
const parsed = CreatedApplication.safeParse(await response.json().catch(() => null));
|
|
45
|
+
if (!parsed.success) {
|
|
46
|
+
// ⚠️ A 2xx Intel cannot read means a principal MAY exist in Gate that Intel cannot record.
|
|
47
|
+
// Nothing has been written on this side yet, so the agent does not come into being; the
|
|
48
|
+
// operator finds an unused application in Gate's list rather than an agent that half works.
|
|
49
|
+
throw new IntelError(502, "agent_application_unavailable", "Gate answered the application creation in a shape Intel cannot read");
|
|
50
|
+
}
|
|
51
|
+
return { id: parsed.data.id, key: parsed.data.key };
|
|
52
|
+
},
|
|
53
|
+
async setEnabled(input) {
|
|
54
|
+
// Both routes are idempotent in Gate, which is what lets a retried archive heal a run that
|
|
55
|
+
// failed between the two writes instead of needing a repair path of its own.
|
|
56
|
+
const response = await call(`/${encodeURIComponent(input.applicationId)}/${input.enabled ? "enable" : "disable"}`, input.token, {});
|
|
57
|
+
// A 404 is the one status worth separating: the Application behind this agent is gone from
|
|
58
|
+
// Gate, and telling the operator that is more use than a generic outage they would retry.
|
|
59
|
+
if (response.status === 404) {
|
|
60
|
+
throw new IntelError(502, "agent_application_missing", "Gate does not know this agent's application any more");
|
|
61
|
+
}
|
|
62
|
+
if (!response.ok)
|
|
63
|
+
throw refusal(response.status);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { QueueProducer } from "./index-queue.types.js";
|
|
3
3
|
export declare const IndexMessage: z.ZodObject<{
|
|
4
|
-
type: z.ZodLiteral<"
|
|
4
|
+
type: z.ZodLiteral<"node.version">;
|
|
5
5
|
versionId: z.ZodString;
|
|
6
6
|
}, z.core.$strict>;
|
|
7
7
|
export type IndexMessage = z.infer<typeof IndexMessage>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export const IndexMessage = z.strictObject({
|
|
3
|
-
type: z.literal("
|
|
3
|
+
type: z.literal("node.version"),
|
|
4
4
|
versionId: z.string().min(1),
|
|
5
5
|
});
|
|
6
6
|
export function createIndexQueue(queue) {
|
|
7
7
|
return {
|
|
8
8
|
async enqueue(versionId) {
|
|
9
|
-
await queue.send({ type: "
|
|
9
|
+
await queue.send({ type: "node.version", versionId });
|
|
10
10
|
},
|
|
11
11
|
};
|
|
12
12
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { NodeIndexTarget } from "../../nodes/nodes.types.js";
|
|
2
2
|
export interface WorkersAiBinding {
|
|
3
3
|
run(model: string, input: {
|
|
4
4
|
text: string[];
|
|
@@ -22,7 +22,7 @@ export interface SemanticHit {
|
|
|
22
22
|
score: number;
|
|
23
23
|
}
|
|
24
24
|
export interface SemanticIndex {
|
|
25
|
-
replace(target:
|
|
25
|
+
replace(target: NodeIndexTarget, content: string): Promise<void>;
|
|
26
26
|
search(query: string, limit: number): Promise<SemanticHit[]>;
|
|
27
27
|
}
|
|
28
28
|
export interface SemanticIndexDeps {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AgentRuntimeDeps, AgentRuntimeService } from "./agent-runtime.types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Intel's door to the agent runtime.
|
|
4
|
+
*
|
|
5
|
+
* ⚠️ The browser never talks to the runtime. It talks to Intel, and Intel forwards — one origin for
|
|
6
|
+
* the page, one session cookie, no CORS, and no Gate token in browser JavaScript. What travels on
|
|
7
|
+
* the forwarded call is the caller's OWN bearer, which the runtime then checks for `agents/run`
|
|
8
|
+
* exactly as it would from any other client. Intel impersonates nobody: there is no service key on
|
|
9
|
+
* this path, and a request that arrives without a usable session never reaches the binding.
|
|
10
|
+
*
|
|
11
|
+
* ⚠️ The three checks below are in this order on purpose. The capability comes first, so a caller
|
|
12
|
+
* who may not drive agents at all causes no storage read; the resource ACL comes second, because it
|
|
13
|
+
* is the question the runtime cannot answer; the binding comes last, so nobody learns whether this
|
|
14
|
+
* deployment has a runtime before they are allowed to ask.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createAgentRuntimeService(deps: AgentRuntimeDeps): AgentRuntimeService;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ProblemDetails } from "@anchrd/intel-contract";
|
|
2
|
+
import { IntelError } from "../shared/intel-error/intel-error.js";
|
|
3
|
+
/**
|
|
4
|
+
* The host a service binding never resolves.
|
|
5
|
+
*
|
|
6
|
+
* A `Request` needs an absolute URL and a binding routes on the path alone, so this name exists
|
|
7
|
+
* only to make one. `.internal` is not a resolvable TLD: a call that ever left this Worker by
|
|
8
|
+
* mistake fails to connect rather than reaching a stranger who registered the domain.
|
|
9
|
+
*/
|
|
10
|
+
const RuntimeOrigin = "https://intel-agent.internal";
|
|
11
|
+
/**
|
|
12
|
+
* Intel's door to the agent runtime.
|
|
13
|
+
*
|
|
14
|
+
* ⚠️ The browser never talks to the runtime. It talks to Intel, and Intel forwards — one origin for
|
|
15
|
+
* the page, one session cookie, no CORS, and no Gate token in browser JavaScript. What travels on
|
|
16
|
+
* the forwarded call is the caller's OWN bearer, which the runtime then checks for `agents/run`
|
|
17
|
+
* exactly as it would from any other client. Intel impersonates nobody: there is no service key on
|
|
18
|
+
* this path, and a request that arrives without a usable session never reaches the binding.
|
|
19
|
+
*
|
|
20
|
+
* ⚠️ The three checks below are in this order on purpose. The capability comes first, so a caller
|
|
21
|
+
* who may not drive agents at all causes no storage read; the resource ACL comes second, because it
|
|
22
|
+
* is the question the runtime cannot answer; the binding comes last, so nobody learns whether this
|
|
23
|
+
* deployment has a runtime before they are allowed to ask.
|
|
24
|
+
*/
|
|
25
|
+
export function createAgentRuntimeService(deps) {
|
|
26
|
+
async function reach(actor, agentId) {
|
|
27
|
+
if (!actor.canRun) {
|
|
28
|
+
throw new IntelError(403, "permission_required", "Permission required");
|
|
29
|
+
}
|
|
30
|
+
const node = await deps.visibleNode(actor, agentId);
|
|
31
|
+
// Not found and not visible answer alike, as everywhere else in the tree: the difference would
|
|
32
|
+
// tell somebody an agent exists that they may not see.
|
|
33
|
+
if (node?.kind !== "agent") {
|
|
34
|
+
throw new IntelError(404, "agent_not_found", "Agent was not found");
|
|
35
|
+
}
|
|
36
|
+
if (!deps.runtime) {
|
|
37
|
+
throw new IntelError(503, "agent_runtime_not_configured", "This installation has no agent runtime");
|
|
38
|
+
}
|
|
39
|
+
return deps.runtime;
|
|
40
|
+
}
|
|
41
|
+
async function forward(input) {
|
|
42
|
+
const runtime = await reach(input.actor, input.agentId);
|
|
43
|
+
const headers = new Headers({ authorization: `Bearer ${input.token}` });
|
|
44
|
+
if (input.body !== undefined)
|
|
45
|
+
headers.set("content-type", "application/json");
|
|
46
|
+
return await runtime.fetch(new Request(`${RuntimeOrigin}/agents/${encodeURIComponent(input.agentId)}${input.path}`, {
|
|
47
|
+
method: input.method,
|
|
48
|
+
headers,
|
|
49
|
+
...(input.body === undefined ? {} : { body: input.body }),
|
|
50
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
forward,
|
|
55
|
+
// A plain fact, not a probe: the binding is either configured or it is not, and nothing is
|
|
56
|
+
// dialled to answer. Unlike `reach` this stands before any per-agent check — it names no agent.
|
|
57
|
+
available: () => deps.runtime !== undefined,
|
|
58
|
+
async request(input) {
|
|
59
|
+
const response = await forward(input);
|
|
60
|
+
const body = await response.json().catch(() => null);
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
const problem = ProblemDetails.safeParse(body);
|
|
63
|
+
// ⚠️ The runtime's own words, and only those. Its refusals are written to be read — by a
|
|
64
|
+
// person on the Log tab and by a model on the MCP surface alike — while anything it could
|
|
65
|
+
// not explain arrives as a generic 500 body. Nothing about the forwarded call is added
|
|
66
|
+
// here: the URL, the binding and above all the bearer stay out of every message.
|
|
67
|
+
throw new IntelError(response.status, problem.success
|
|
68
|
+
? (problem.data.code ?? "agent_runtime_refused")
|
|
69
|
+
: "agent_runtime_refused", problem.success
|
|
70
|
+
? (problem.data.detail ?? problem.data.title)
|
|
71
|
+
: "The agent runtime refused this call");
|
|
72
|
+
}
|
|
73
|
+
return body;
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Node } from "@anchrd/intel-contract";
|
|
2
|
+
import type { Actor } from "../nodes/nodes.types.js";
|
|
3
|
+
/**
|
|
4
|
+
* The agent runtime Worker, as Intel is allowed to see it.
|
|
5
|
+
*
|
|
6
|
+
* One method, because that is all a service binding is. The Cloudflare adapter hands the binding
|
|
7
|
+
* over unchanged; nothing below this line knows it is one, so the whole seam is testable with a
|
|
8
|
+
* plain object that records what it was asked.
|
|
9
|
+
*/
|
|
10
|
+
export interface AgentRuntimeBinding {
|
|
11
|
+
fetch(request: Request): Promise<Response>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Who is driving the agent.
|
|
15
|
+
*
|
|
16
|
+
* ⚠️ `canRun` is the caller's Gate capability, resolved once at the door — never something a body,
|
|
17
|
+
* an MCP argument or a definition may say. It is spelled beside the actor rather than derived here
|
|
18
|
+
* for the same reason `FlowActor` spells `canRun`: the service must not need a Gate client.
|
|
19
|
+
*/
|
|
20
|
+
export interface AgentActor extends Actor {
|
|
21
|
+
canRun: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface AgentRuntimeDeps {
|
|
24
|
+
/**
|
|
25
|
+
* Absent where a deployment runs no agent Worker. Every call then refuses by name instead of
|
|
26
|
+
* failing somewhere unreadable — a customer may deploy Intel without agents.
|
|
27
|
+
*/
|
|
28
|
+
runtime?: AgentRuntimeBinding;
|
|
29
|
+
/**
|
|
30
|
+
* The tree's own visibility lookup, unchanged on the way through. It is the check the runtime
|
|
31
|
+
* cannot make: the runtime knows Gate capabilities and nothing about Intel's resource ACLs, so
|
|
32
|
+
* "may this person drive agents at all" is its question and "may they reach THIS agent" is ours.
|
|
33
|
+
*/
|
|
34
|
+
visibleNode(actor: Actor, nodeId: string): Promise<Node | null>;
|
|
35
|
+
}
|
|
36
|
+
export interface ForwardInput {
|
|
37
|
+
actor: AgentActor;
|
|
38
|
+
/** The caller's own Gate bearer, passed on unchanged. Never a service key (D19). */
|
|
39
|
+
token: string;
|
|
40
|
+
agentId: string;
|
|
41
|
+
method: "GET" | "POST";
|
|
42
|
+
/** The path below `/agents/:agentId`, exactly as the runtime mounts it. */
|
|
43
|
+
path: string;
|
|
44
|
+
body?: string;
|
|
45
|
+
signal?: AbortSignal;
|
|
46
|
+
}
|
|
47
|
+
export interface AgentRuntimeService {
|
|
48
|
+
/** The browser's way through: the runtime's answer, body and headers untouched. */
|
|
49
|
+
forward(input: ForwardInput): Promise<Response>;
|
|
50
|
+
/** The same door for a caller that wants the answer, not the response — Intel MCP uses this. */
|
|
51
|
+
request(input: ForwardInput): Promise<unknown>;
|
|
52
|
+
/**
|
|
53
|
+
* Whether this deployment has a runtime at all (#190). The answer `/capabilities` gives to an
|
|
54
|
+
* authenticated caller so the UI can stop offering agents instead of guessing from a 503.
|
|
55
|
+
*/
|
|
56
|
+
available(): boolean;
|
|
57
|
+
}
|