@retinue/agentkit 0.1.0 → 0.3.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 +59 -277
- package/dist/adapters/audio/openai.d.ts +36 -0
- package/dist/adapters/audio/openai.js +136 -0
- package/dist/adapters/bullmq/lock.d.ts +26 -2
- package/dist/adapters/embeddings/openai.d.ts +45 -0
- package/dist/adapters/embeddings/openai.js +109 -0
- package/dist/adapters/memory/connections.d.ts +10 -0
- package/dist/adapters/memory/connections.js +87 -0
- package/dist/adapters/memory/graph.d.ts +17 -0
- package/dist/adapters/memory/graph.js +267 -0
- package/dist/adapters/memory/index.d.ts +3 -0
- package/dist/adapters/memory/index.js +3 -0
- package/dist/adapters/memory/rate-limit.d.ts +14 -0
- package/dist/adapters/memory/rate-limit.js +28 -0
- package/dist/adapters/memory/runtime.js +0 -0
- package/dist/adapters/postgres/connections.d.ts +15 -0
- package/dist/adapters/postgres/connections.js +134 -0
- package/dist/adapters/postgres/graph.d.ts +24 -0
- package/dist/adapters/postgres/graph.js +325 -0
- package/dist/adapters/postgres/index.d.ts +2 -0
- package/dist/adapters/postgres/index.js +2 -0
- package/dist/adapters/postgres/migrations.js +198 -0
- package/dist/adapters/postgres/run-store.js +26 -2
- package/dist/adapters/postgres/schema.d.ts +61 -2
- package/dist/adapters/postgres/schema.js +95 -10
- package/dist/adapters/redis/index.d.ts +1 -0
- package/dist/adapters/redis/index.js +1 -0
- package/dist/adapters/redis/rate-limit.d.ts +46 -0
- package/dist/adapters/redis/rate-limit.js +55 -0
- package/dist/adapters/supabase/index.d.ts +15 -0
- package/dist/adapters/supabase/index.js +15 -0
- package/dist/adapters/supabase/rls.js +33 -0
- package/dist/agents/agent.d.ts +99 -1
- package/dist/agents/agent.js +215 -16
- package/dist/agents/define.js +24 -4
- package/dist/agents/engine.d.ts +48 -0
- package/dist/agents/engine.js +370 -13
- package/dist/audio/index.d.ts +151 -0
- package/dist/audio/index.js +183 -0
- package/dist/capabilities/index.d.ts +5 -1
- package/dist/capabilities/index.js +23 -0
- package/dist/capabilities/runtime.d.ts +8 -0
- package/dist/connections/cipher.d.ts +103 -0
- package/dist/connections/cipher.js +141 -0
- package/dist/connections/index.d.ts +156 -0
- package/dist/connections/index.js +72 -0
- package/dist/connections/oauth/client.d.ts +84 -0
- package/dist/connections/oauth/client.js +141 -0
- package/dist/connections/oauth/index.d.ts +166 -0
- package/dist/connections/oauth/index.js +226 -0
- package/dist/connections/oauth/service.d.ts +90 -0
- package/dist/connections/oauth/service.js +132 -0
- package/dist/connections/pause.d.ts +68 -0
- package/dist/connections/pause.js +97 -0
- package/dist/connections/resolver.d.ts +59 -0
- package/dist/connections/resolver.js +138 -0
- package/dist/connections/resume.d.ts +64 -0
- package/dist/connections/resume.js +99 -0
- package/dist/connections/vault-cipher.d.ts +95 -0
- package/dist/connections/vault-cipher.js +206 -0
- package/dist/core/budget.d.ts +55 -0
- package/dist/core/budget.js +56 -0
- package/dist/core/content-parts.d.ts +26 -2
- package/dist/core/content-parts.js +1 -0
- package/dist/core/context.d.ts +25 -0
- package/dist/core/errors.d.ts +1 -1
- package/dist/core/errors.js +15 -0
- package/dist/core/events.d.ts +110 -2
- package/dist/core/events.js +33 -2
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/core/validation.js +19 -0
- package/dist/documents/index.d.ts +14 -0
- package/dist/documents/parsers/text.d.ts +16 -0
- package/dist/documents/parsers/text.js +54 -2
- package/dist/entries/connections.d.ts +10 -0
- package/dist/entries/connections.js +10 -0
- package/dist/entries/guardrails.d.ts +14 -0
- package/dist/entries/guardrails.js +14 -0
- package/dist/entries/knowledge.d.ts +17 -0
- package/dist/entries/knowledge.js +16 -0
- package/dist/entries/mcp-server.d.ts +9 -0
- package/dist/entries/mcp-server.js +9 -0
- package/dist/entries/runtime.d.ts +10 -0
- package/dist/entries/runtime.js +8 -0
- package/dist/entries/testing.d.ts +28 -0
- package/dist/entries/testing.js +28 -0
- package/dist/graphql/resolvers.d.ts +7 -1
- package/dist/graphql/resolvers.js +20 -0
- package/dist/graphql/schema.d.ts +1 -1
- package/dist/graphql/schema.js +44 -0
- package/dist/guardrails/index.d.ts +115 -0
- package/dist/guardrails/index.js +108 -0
- package/dist/guardrails/moderation.d.ts +53 -0
- package/dist/guardrails/moderation.js +75 -0
- package/dist/guardrails/pii.d.ts +75 -0
- package/dist/guardrails/pii.js +193 -0
- package/dist/knowledge/communities.d.ts +166 -0
- package/dist/knowledge/communities.js +377 -0
- package/dist/knowledge/graph-global.d.ts +153 -0
- package/dist/knowledge/graph-global.js +246 -0
- package/dist/knowledge/graph-retrieval.d.ts +150 -0
- package/dist/knowledge/graph-retrieval.js +303 -0
- package/dist/knowledge/graph.d.ts +223 -0
- package/dist/knowledge/graph.js +369 -0
- package/dist/knowledge/index.d.ts +25 -0
- package/dist/knowledge/index.js +37 -1
- package/dist/knowledge/navigate.d.ts +89 -0
- package/dist/knowledge/navigate.js +107 -0
- package/dist/knowledge/retrieval.d.ts +98 -5
- package/dist/knowledge/retrieval.js +158 -28
- package/dist/mcp-server/index.d.ts +168 -0
- package/dist/mcp-server/index.js +175 -0
- package/dist/models/extraction.d.ts +73 -0
- package/dist/models/extraction.js +118 -0
- package/dist/models/index.d.ts +40 -1
- package/dist/models/index.js +22 -1
- package/dist/models/pricing.d.ts +2 -0
- package/dist/models/pricing.js +17 -1
- package/dist/models/provider-factory.js +9 -7
- package/dist/models/streaming.d.ts +111 -1
- package/dist/models/streaming.js +184 -3
- package/dist/persistence/index.d.ts +230 -0
- package/dist/persistence/index.js +2 -0
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +12 -0
- package/dist/runtime/worker.d.ts +36 -1
- package/dist/runtime/worker.js +37 -4
- package/dist/security/checklist.js +55 -0
- package/dist/security/findings.js +18 -9
- package/dist/server/bin.d.ts +19 -0
- package/dist/server/bin.js +226 -0
- package/dist/server/boot.d.ts +20 -2
- package/dist/server/boot.js +29 -3
- package/dist/server/cli.d.ts +13 -0
- package/dist/server/cli.js +7 -4
- package/dist/server/doctor.d.ts +74 -0
- package/dist/server/doctor.js +280 -0
- package/dist/skills/catalogue.d.ts +49 -0
- package/dist/skills/catalogue.js +61 -0
- package/dist/skills/context.d.ts +61 -0
- package/dist/skills/context.js +107 -0
- package/dist/skills/index.d.ts +2 -0
- package/dist/skills/index.js +2 -0
- package/dist/telemetry/spans.js +17 -0
- package/dist/testing/conformance/artifact-exports.d.ts +20 -0
- package/dist/testing/conformance/artifact-exports.js +172 -0
- package/dist/testing/conformance/artifacts.d.ts +11 -0
- package/dist/testing/conformance/artifacts.js +316 -0
- package/dist/testing/conformance/audio.d.ts +38 -0
- package/dist/testing/conformance/audio.js +145 -0
- package/dist/testing/conformance/capability.d.ts +23 -0
- package/dist/testing/conformance/capability.js +27 -0
- package/dist/testing/conformance/checkpoint-store.d.ts +15 -0
- package/dist/testing/conformance/checkpoint-store.js +72 -0
- package/dist/testing/conformance/connections.d.ts +14 -0
- package/dist/testing/conformance/connections.js +171 -0
- package/dist/testing/conformance/conversation-store.d.ts +10 -0
- package/dist/testing/conformance/conversation-store.js +60 -0
- package/dist/testing/conformance/evaluation.d.ts +10 -0
- package/dist/testing/conformance/evaluation.js +295 -0
- package/dist/testing/conformance/files.d.ts +19 -0
- package/dist/testing/conformance/files.js +454 -0
- package/dist/testing/conformance/flows.d.ts +16 -0
- package/dist/testing/conformance/flows.js +193 -0
- package/dist/testing/conformance/graph.d.ts +22 -0
- package/dist/testing/conformance/graph.js +500 -0
- package/dist/testing/conformance/hitl.d.ts +25 -0
- package/dist/testing/conformance/hitl.js +523 -0
- package/dist/testing/conformance/index.d.ts +163 -0
- package/dist/testing/conformance/index.js +321 -0
- package/dist/testing/conformance/invariants.d.ts +23 -0
- package/dist/testing/conformance/invariants.js +80 -0
- package/dist/testing/conformance/knowledge.d.ts +41 -0
- package/dist/testing/conformance/knowledge.js +592 -0
- package/dist/testing/conformance/parents.d.ts +50 -0
- package/dist/testing/conformance/parents.js +39 -0
- package/dist/testing/conformance/rate-limit.d.ts +25 -0
- package/dist/testing/conformance/rate-limit.js +71 -0
- package/dist/testing/conformance/records.d.ts +36 -0
- package/dist/testing/conformance/records.js +400 -0
- package/dist/testing/conformance/rollups.d.ts +30 -0
- package/dist/testing/conformance/rollups.js +425 -0
- package/dist/testing/conformance/run-coordinator.d.ts +27 -0
- package/dist/testing/conformance/run-coordinator.js +150 -0
- package/dist/testing/conformance/run-event-log.d.ts +9 -0
- package/dist/testing/conformance/run-event-log.js +138 -0
- package/dist/testing/conformance/run-store.d.ts +12 -0
- package/dist/testing/conformance/run-store.js +294 -0
- package/dist/testing/conformance/session-state.d.ts +38 -0
- package/dist/testing/conformance/session-state.js +198 -0
- package/dist/testing/conformance/usage-limits.d.ts +10 -0
- package/dist/testing/conformance/usage-limits.js +309 -0
- package/dist/testing/conformance.d.ts +8 -0
- package/dist/testing/conformance.js +8 -0
- package/dist/testing/memory-backend.d.ts +39 -0
- package/dist/testing/memory-backend.js +41 -0
- package/dist/testing/pglite.d.ts +55 -0
- package/dist/testing/pglite.js +78 -0
- package/dist/testing/stub-model.d.ts +58 -0
- package/dist/testing/stub-model.js +71 -0
- package/dist/testing/supabase-storage-double.d.ts +35 -0
- package/dist/testing/supabase-storage-double.js +101 -0
- package/dist/toolkit/files.d.ts +125 -0
- package/dist/toolkit/files.js +320 -0
- package/dist/toolkit/http.d.ts +27 -0
- package/dist/toolkit/http.js +48 -0
- package/dist/toolkit/index.d.ts +31 -1
- package/dist/toolkit/index.js +26 -1
- package/dist/toolkit/mime.d.ts +97 -0
- package/dist/toolkit/mime.js +233 -0
- package/dist/toolkit/sandbox.d.ts +119 -0
- package/dist/toolkit/sandbox.js +239 -0
- package/dist/toolkit/ssrf.d.ts +139 -0
- package/dist/toolkit/ssrf.js +349 -0
- package/dist/toolkit/vendor.d.ts +91 -0
- package/dist/toolkit/vendor.js +153 -0
- package/dist/toolkit/web.d.ts +13 -0
- package/dist/toolkit/web.js +7 -1
- package/dist/tools/budget.d.ts +28 -0
- package/dist/tools/budget.js +35 -0
- package/dist/tools/credentials.d.ts +316 -0
- package/dist/tools/credentials.js +369 -0
- package/dist/tools/define.d.ts +45 -0
- package/dist/tools/define.js +26 -0
- package/dist/tools/find.d.ts +109 -0
- package/dist/tools/find.js +210 -0
- package/dist/tools/index.d.ts +35 -2
- package/dist/tools/index.js +11 -0
- package/dist/tools/library/audio.d.ts +63 -0
- package/dist/tools/library/audio.js +148 -0
- package/dist/tools/library/fs.d.ts +24 -0
- package/dist/tools/library/fs.js +102 -0
- package/dist/tools/library/index.d.ts +37 -2
- package/dist/tools/library/index.js +47 -0
- package/dist/tools/library/shell.d.ts +45 -0
- package/dist/tools/library/shell.js +70 -0
- package/dist/tools/meta-tools.js +8 -0
- package/dist/tools/registry.d.ts +146 -0
- package/dist/tools/registry.js +250 -4
- package/dist/usage/index.d.ts +21 -0
- package/dist/usage/index.js +1 -0
- package/dist/usage/rate-limit.d.ts +122 -0
- package/dist/usage/rate-limit.js +131 -0
- package/dist/usage/recorder.js +3 -0
- package/package.json +33 -2
|
@@ -72,6 +72,13 @@ export const TENANT_SCOPED_TABLES = [
|
|
|
72
72
|
{ table: "idempotency_keys" },
|
|
73
73
|
{ table: "skills" },
|
|
74
74
|
{ table: "mcp_connections" },
|
|
75
|
+
/**
|
|
76
|
+
* #261. A tenant's third-party credentials, and therefore the table where a missing policy would be worst:
|
|
77
|
+
* every row is somebody's access to somebody else's system, and the plain `tenant_id` predicate is exactly
|
|
78
|
+
* the isolation the port already enforces in its `WHERE` clauses. Defence in depth, and #91 is the reminder
|
|
79
|
+
* that a method accepting a tenant scope and not using it typechecks perfectly.
|
|
80
|
+
*/
|
|
81
|
+
{ table: "connections" },
|
|
75
82
|
{ table: "principal_memory", extraPredicate: PRINCIPAL_PREDICATE },
|
|
76
83
|
// `blobs`, not the SPEC's `blob_refs`: BlobStore stores the value, and the metadata-and-pointer
|
|
77
84
|
// design belongs to FileMetadataStore (#129) / ArtifactStore (#133).
|
|
@@ -98,6 +105,32 @@ export const TENANT_SCOPED_TABLES = [
|
|
|
98
105
|
*/
|
|
99
106
|
{ table: "flow_definitions" },
|
|
100
107
|
{ table: "flow_executions" },
|
|
108
|
+
/**
|
|
109
|
+
* #271. The knowledge graph, all five tables, and they belong here rather than beside `knowledge_chunks`
|
|
110
|
+
* in the vector list: none of them needs pgvector, so they exist in every deployment and can be protected
|
|
111
|
+
* unconditionally.
|
|
112
|
+
*
|
|
113
|
+
* Worth stating why the *settings* table needs a policy as much as the content ones. `knowledge_graph_settings`
|
|
114
|
+
* holds one boolean, so it looks harmless — but it is the switch that decides whether a tenant is paying for
|
|
115
|
+
* extraction, and a missing policy would let one tenant read, and worse write, another's. Turning a
|
|
116
|
+
* neighbour's GraphRAG on is a bill they did not agree to.
|
|
117
|
+
*/
|
|
118
|
+
{ table: "knowledge_graph_settings" },
|
|
119
|
+
{ table: "knowledge_graph_sources" },
|
|
120
|
+
/**
|
|
121
|
+
* The contributions table is the one to get right. It holds the entities and relationships each source
|
|
122
|
+
* asserted, as JSON — which is to say, the substance of the documents themselves in condensed form. A leak
|
|
123
|
+
* here is a leak of what a tenant's corpus says, not merely of which entities exist.
|
|
124
|
+
*/
|
|
125
|
+
{ table: "knowledge_graph_contributions" },
|
|
126
|
+
{ table: "knowledge_graph_entities" },
|
|
127
|
+
{ table: "knowledge_graph_relationships" },
|
|
128
|
+
/**
|
|
129
|
+
* #272. Community summaries are **generated prose about a tenant's corpus** — a paraphrase of what their
|
|
130
|
+
* documents say, which is if anything more sensitive than the entity names next door. A missing policy here
|
|
131
|
+
* would leak the substance of a corpus rather than its index.
|
|
132
|
+
*/
|
|
133
|
+
{ table: "knowledge_graph_communities" },
|
|
101
134
|
];
|
|
102
135
|
/**
|
|
103
136
|
* Tables that deliberately have no tenant policy, each with the reason.
|
package/dist/agents/agent.d.ts
CHANGED
|
@@ -15,11 +15,52 @@ import { type ProviderCredentials } from "../models/provider-factory.js";
|
|
|
15
15
|
import type { ModelProvider } from "../models/index.js";
|
|
16
16
|
import type { AuthorizationPolicy } from "../authorization/index.js";
|
|
17
17
|
import { type ContextProvider } from "../context/index.js";
|
|
18
|
-
import { type ToolProvider } from "../tools/index.js";
|
|
18
|
+
import { type ShadowRecorder, type ToolProvider, type ToolSearch, type ToolsetResolver } from "../tools/index.js";
|
|
19
|
+
import type { TokenBudget } from "../core/budget.js";
|
|
19
20
|
import { type AgentEngine, type ProcessOutcome } from "../runtime/index.js";
|
|
21
|
+
import type { Guardrail } from "../guardrails/index.js";
|
|
22
|
+
import { type SkillResolver } from "../skills/index.js";
|
|
20
23
|
import { type ResolvedModelInfo } from "./engine.js";
|
|
21
24
|
import type { AgentManifest } from "./index.js";
|
|
22
25
|
import { type AgentManifestInput } from "./define.js";
|
|
26
|
+
/**
|
|
27
|
+
* The policy this agent runs under — task #244, the interpreter for `authorizationPolicyId`.
|
|
28
|
+
*
|
|
29
|
+
* The field was declared and read by nothing, so an agent naming `"restricted"` ran under whatever the host had
|
|
30
|
+
* wired — very possibly the permissive default. Three rules, and the third is the one that matters:
|
|
31
|
+
*
|
|
32
|
+
* 1. A map is supplied and contains the id → that policy.
|
|
33
|
+
* 2. No map, and the id is `defineAgent`'s `"default"` → the single wired policy, or the permissive default.
|
|
34
|
+
* This is the normal case and stays a one-liner.
|
|
35
|
+
* 3. **Any other combination is an error.** An id the deployment cannot honour must never fall through to the
|
|
36
|
+
* permissive default: an agent asking to run under a narrow policy and silently getting allow-all is the
|
|
37
|
+
* worst possible reading of this field, and it is the reading it had. Failing at construction is loud, early
|
|
38
|
+
* and cheap.
|
|
39
|
+
*
|
|
40
|
+
* Note the platform does not check that a named policy is *narrower* than any other. It cannot: a policy is an
|
|
41
|
+
* interface the host implements, and composing two of them into an intersection would mean second-guessing a
|
|
42
|
+
* deployment's own authorization. What the platform guarantees is that the policy an agent named is the policy
|
|
43
|
+
* it got, or the run does not start.
|
|
44
|
+
*/
|
|
45
|
+
export declare const selectAuthorization: (config: Pick<CreateAgentConfig, "authorization" | "authorizationPolicies">, manifest: Pick<AgentManifest, "authorizationPolicyId" | "id">) => AuthorizationPolicy;
|
|
46
|
+
/**
|
|
47
|
+
* The providers this agent asked for, in the order it asked — task #244.
|
|
48
|
+
*
|
|
49
|
+
* `AgentManifest.contextProviderIds` was declared and read by nothing, so a manifest naming two of four wired
|
|
50
|
+
* providers got all four, and naming none got all of them too. Two decisions make the field meaningful without
|
|
51
|
+
* making it a trap:
|
|
52
|
+
*
|
|
53
|
+
* - **An empty list means every wired provider**, not none. `defineAgent` defaults it to `[]`, so treating empty
|
|
54
|
+
* as "no context" would silently strip the memory, notes and attachments from every agent already written
|
|
55
|
+
* against the default. The field is a *selection*, and no selection means no narrowing.
|
|
56
|
+
* - **A named id that is not wired is an error**, not a silent omission. The failure it prevents is the one worth
|
|
57
|
+
* preventing: an agent whose manifest asks for `principal-memory`, a typo or a missing wire, and an assistant
|
|
58
|
+
* that quietly remembers nothing. That reads exactly like a model that chose not to use its memory.
|
|
59
|
+
*
|
|
60
|
+
* Order follows the manifest, because section order is prompt order and the manifest is where an author can see
|
|
61
|
+
* and control it.
|
|
62
|
+
*/
|
|
63
|
+
export declare const selectContextProviders: (wired: readonly ContextProvider[], manifest: Pick<AgentManifest, "contextProviderIds" | "id">) => readonly ContextProvider[];
|
|
23
64
|
export type CreateAgentConfig = {
|
|
24
65
|
readonly manifest: AgentManifestInput;
|
|
25
66
|
/** Model catalog; defaults to a small Anthropic catalog (smart/fast). */
|
|
@@ -38,7 +79,52 @@ export type CreateAgentConfig = {
|
|
|
38
79
|
*/
|
|
39
80
|
readonly randomHex?: (bytes: number) => string;
|
|
40
81
|
readonly authorization?: AuthorizationPolicy;
|
|
82
|
+
/**
|
|
83
|
+
* Named policies a manifest may select with `authorizationPolicyId` — task #244.
|
|
84
|
+
*
|
|
85
|
+
* Absent is the normal case: one `authorization` (or the permissive default), and every manifest carrying
|
|
86
|
+
* `defineAgent`'s `"default"`. Supplying a map is how a deployment runs several agents under different
|
|
87
|
+
* policies — a customer-facing agent under a narrow one, an internal agent under a wider one — without the
|
|
88
|
+
* host having to build a separate registry per agent.
|
|
89
|
+
*/
|
|
90
|
+
readonly authorizationPolicies?: Readonly<Record<string, AuthorizationPolicy>>;
|
|
91
|
+
/**
|
|
92
|
+
* Checks to run before the model sees a turn and before anything leaves it — REQ-046 (#205), AC-5.
|
|
93
|
+
*
|
|
94
|
+
* Here so a host can add one without composing the runtime by hand: this facade exists to be the short path,
|
|
95
|
+
* and a guardrail that could only be wired through the long one would be a guardrail most deployments never
|
|
96
|
+
* add.
|
|
97
|
+
*/
|
|
98
|
+
readonly guardrails?: readonly Guardrail[];
|
|
99
|
+
/**
|
|
100
|
+
* Search over the catalogue, which is what makes `find_tools` exist — REQ-045 (#204), task #210.
|
|
101
|
+
*
|
|
102
|
+
* Absent means no `find_tools`. Wire it with `createToolSearch()` for keyword search, or pass an
|
|
103
|
+
* `EmbeddingProvider` to it for hybrid — and see `tools/find.ts` on why keyword-only is the honest default.
|
|
104
|
+
*/
|
|
105
|
+
readonly toolSearch?: ToolSearch;
|
|
106
|
+
/** A ceiling in tokens on the tool list handed to the model — task #210, AC-3. Absent means no ceiling. */
|
|
107
|
+
readonly catalogBudget?: TokenBudget;
|
|
108
|
+
/** A tenant's category switches, applied before authorization — task #210, AC-4. */
|
|
109
|
+
readonly toolsets?: ToolsetResolver;
|
|
110
|
+
/**
|
|
111
|
+
* A skill resolver — task #244, and what makes `manifest.skillPolicy` mean something.
|
|
112
|
+
*
|
|
113
|
+
* Wiring is the toggle, the rule `toolSearch` already follows. Supplying one adds a skills catalogue section
|
|
114
|
+
* to the prompt (names and descriptions, filtered by the manifest's `assigned`/`allowTenantSkills`) and makes
|
|
115
|
+
* `load_skill` real; omitting it means neither is advertised.
|
|
116
|
+
*/
|
|
117
|
+
readonly skills?: SkillResolver;
|
|
41
118
|
readonly tenantId?: string;
|
|
119
|
+
/**
|
|
120
|
+
* Where a shadow run's suppressed writes go — required to run one at all.
|
|
121
|
+
*
|
|
122
|
+
* Without it `createAgent` cannot run a shadow turn: the registry refuses a gated tool when
|
|
123
|
+
* `context.shadow` is true and no recorder is configured, which is the correct fail-closed rule but meant
|
|
124
|
+
* this runner had no way to satisfy it. Parity measurement needs a run driven to completion in one process,
|
|
125
|
+
* and this is that seam.
|
|
126
|
+
*/
|
|
127
|
+
readonly shadow?: ShadowRecorder;
|
|
42
128
|
/** Test/advanced seam: override how a manifest resolves to a model (e.g. a mock model). */
|
|
43
129
|
readonly resolveModel?: (manifest: AgentManifest, context: ExecutionContext) => ResolvedModelInfo;
|
|
44
130
|
/** Test/advanced seam: supply the engine directly instead of building the default one. */
|
|
@@ -50,6 +136,18 @@ export type RunInput = {
|
|
|
50
136
|
readonly message: string;
|
|
51
137
|
readonly principalId?: string;
|
|
52
138
|
readonly roleIds?: readonly string[];
|
|
139
|
+
/**
|
|
140
|
+
* Run with every gated effect suppressed and recorded instead of performed.
|
|
141
|
+
*
|
|
142
|
+
* Per-run rather than per-agent, because the same agent serves both: a parity harness shadows one turn and
|
|
143
|
+
* runs the next for real. `shadow` without `config.shadow` is refused by the registry rather than performed
|
|
144
|
+
* — announcing a shadow run with nowhere to record it is not a licence to publish.
|
|
145
|
+
*
|
|
146
|
+
* Note what shadow mode does **not** suppress: an `internal-write` still happens, so a shadow run really
|
|
147
|
+
* does create drafts. It measures everything up to the external write and nothing after it, because what an
|
|
148
|
+
* agent does after publishing cannot be observed without publishing.
|
|
149
|
+
*/
|
|
150
|
+
readonly shadow?: boolean;
|
|
53
151
|
};
|
|
54
152
|
export type RunResult = {
|
|
55
153
|
readonly runId: string;
|
package/dist/agents/agent.js
CHANGED
|
@@ -17,14 +17,95 @@ import { createProviderFactory, } from "../models/provider-factory.js";
|
|
|
17
17
|
import { gatherSections } from "../context/index.js";
|
|
18
18
|
import { randomBytes } from "node:crypto";
|
|
19
19
|
import { makeNonce, renderContextBlock } from "../security/prompt-safety.js";
|
|
20
|
-
import { createToolRegistry } from "../tools/index.js";
|
|
20
|
+
import { createToolRegistry, } from "../tools/index.js";
|
|
21
21
|
import { createDurableWorker } from "../runtime/index.js";
|
|
22
22
|
import { createMemoryCheckpointStore, createMemoryRunEventLog, createMemoryRunStore, } from "../adapters/memory/runtime.js";
|
|
23
23
|
import { createMemoryConversationStore } from "../adapters/memory/index.js";
|
|
24
24
|
import { createMemoryEventBus } from "../runtime/index.js";
|
|
25
25
|
import { createMemoryMessageStore } from "../adapters/memory/message-store.js";
|
|
26
|
+
import { createSkillBodyLoader, createSkillCatalogueProvider, } from "../skills/index.js";
|
|
26
27
|
import { createDefaultEngine } from "./engine.js";
|
|
27
28
|
import { DEFAULT_MODEL_CATALOG, DEFAULT_ROLE_ASSIGNMENTS, defineAgent, } from "./define.js";
|
|
29
|
+
/**
|
|
30
|
+
* The policy this agent runs under — task #244, the interpreter for `authorizationPolicyId`.
|
|
31
|
+
*
|
|
32
|
+
* The field was declared and read by nothing, so an agent naming `"restricted"` ran under whatever the host had
|
|
33
|
+
* wired — very possibly the permissive default. Three rules, and the third is the one that matters:
|
|
34
|
+
*
|
|
35
|
+
* 1. A map is supplied and contains the id → that policy.
|
|
36
|
+
* 2. No map, and the id is `defineAgent`'s `"default"` → the single wired policy, or the permissive default.
|
|
37
|
+
* This is the normal case and stays a one-liner.
|
|
38
|
+
* 3. **Any other combination is an error.** An id the deployment cannot honour must never fall through to the
|
|
39
|
+
* permissive default: an agent asking to run under a narrow policy and silently getting allow-all is the
|
|
40
|
+
* worst possible reading of this field, and it is the reading it had. Failing at construction is loud, early
|
|
41
|
+
* and cheap.
|
|
42
|
+
*
|
|
43
|
+
* Note the platform does not check that a named policy is *narrower* than any other. It cannot: a policy is an
|
|
44
|
+
* interface the host implements, and composing two of them into an intersection would mean second-guessing a
|
|
45
|
+
* deployment's own authorization. What the platform guarantees is that the policy an agent named is the policy
|
|
46
|
+
* it got, or the run does not start.
|
|
47
|
+
*/
|
|
48
|
+
export const selectAuthorization = (config, manifest) => {
|
|
49
|
+
const id = manifest.authorizationPolicyId ?? "default";
|
|
50
|
+
const named = config.authorizationPolicies;
|
|
51
|
+
if (named !== undefined) {
|
|
52
|
+
const chosen = named[id];
|
|
53
|
+
if (chosen !== undefined)
|
|
54
|
+
return chosen;
|
|
55
|
+
throw new AgentPlatformError({
|
|
56
|
+
code: "capability_unavailable",
|
|
57
|
+
message: `agent "${manifest.id}" runs under authorization policy "${id}" and no such policy is registered ` +
|
|
58
|
+
`(registered: ${Object.keys(named).map((k) => `"${k}"`).join(", ") || "none"}). Refusing rather than ` +
|
|
59
|
+
"falling back — an agent that asked for a narrow policy and silently got a permissive one is the " +
|
|
60
|
+
"failure this field exists to prevent.",
|
|
61
|
+
retryable: false,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (id !== "default")
|
|
65
|
+
throw new AgentPlatformError({
|
|
66
|
+
code: "capability_unavailable",
|
|
67
|
+
message: `agent "${manifest.id}" runs under authorization policy "${id}" and none is registered. Pass ` +
|
|
68
|
+
"`authorizationPolicies: { \"" +
|
|
69
|
+
id +
|
|
70
|
+
"\": … }`, or leave the manifest's `authorizationPolicyId` at \"default\".",
|
|
71
|
+
retryable: false,
|
|
72
|
+
});
|
|
73
|
+
return config.authorization ?? allowAllAuthorization();
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* The providers this agent asked for, in the order it asked — task #244.
|
|
77
|
+
*
|
|
78
|
+
* `AgentManifest.contextProviderIds` was declared and read by nothing, so a manifest naming two of four wired
|
|
79
|
+
* providers got all four, and naming none got all of them too. Two decisions make the field meaningful without
|
|
80
|
+
* making it a trap:
|
|
81
|
+
*
|
|
82
|
+
* - **An empty list means every wired provider**, not none. `defineAgent` defaults it to `[]`, so treating empty
|
|
83
|
+
* as "no context" would silently strip the memory, notes and attachments from every agent already written
|
|
84
|
+
* against the default. The field is a *selection*, and no selection means no narrowing.
|
|
85
|
+
* - **A named id that is not wired is an error**, not a silent omission. The failure it prevents is the one worth
|
|
86
|
+
* preventing: an agent whose manifest asks for `principal-memory`, a typo or a missing wire, and an assistant
|
|
87
|
+
* that quietly remembers nothing. That reads exactly like a model that chose not to use its memory.
|
|
88
|
+
*
|
|
89
|
+
* Order follows the manifest, because section order is prompt order and the manifest is where an author can see
|
|
90
|
+
* and control it.
|
|
91
|
+
*/
|
|
92
|
+
export const selectContextProviders = (wired, manifest) => {
|
|
93
|
+
const asked = manifest.contextProviderIds ?? [];
|
|
94
|
+
if (asked.length === 0)
|
|
95
|
+
return wired;
|
|
96
|
+
const byId = new Map(wired.map((p) => [p.id, p]));
|
|
97
|
+
const missing = asked.filter((id) => !byId.has(id));
|
|
98
|
+
if (missing.length > 0)
|
|
99
|
+
throw new AgentPlatformError({
|
|
100
|
+
code: "capability_unavailable",
|
|
101
|
+
message: `agent "${manifest.id}" asks for context provider(s) ${missing.map((m) => `"${m}"`).join(", ")} and ` +
|
|
102
|
+
`nothing wired supplies them (wired: ${wired.map((p) => `"${p.id}"`).join(", ") || "none"}). An agent ` +
|
|
103
|
+
"that silently runs without the context it declared is indistinguishable from a model choosing not to " +
|
|
104
|
+
"use it.",
|
|
105
|
+
retryable: false,
|
|
106
|
+
});
|
|
107
|
+
return asked.map((id) => byId.get(id));
|
|
108
|
+
};
|
|
28
109
|
/** Permissive policy used by the embedded facade when a caller wires tools but no authorization. */
|
|
29
110
|
const allowAllAuthorization = () => ({
|
|
30
111
|
async can() {
|
|
@@ -55,8 +136,28 @@ export const createAgent = (config) => {
|
|
|
55
136
|
roles: config.roleAssignments ?? DEFAULT_ROLE_ASSIGNMENTS,
|
|
56
137
|
});
|
|
57
138
|
const providerFactory = createProviderFactory({ credentials: config.providerCredentials ?? {} });
|
|
58
|
-
const authorization = config
|
|
59
|
-
|
|
139
|
+
const authorization = selectAuthorization(config, manifest);
|
|
140
|
+
/**
|
|
141
|
+
* Skills, when a resolver is wired — #244.
|
|
142
|
+
*
|
|
143
|
+
* Both halves read the *same* policy, and that is the point: `createSkillBodyLoader` re-derives the catalogue
|
|
144
|
+
* before loading, so `assigned` and `allowTenantSkills` gate loading as well as listing. A policy that
|
|
145
|
+
* filtered the list but not the load would be no policy at all — a model that guessed a name would get it.
|
|
146
|
+
*/
|
|
147
|
+
const skillPolicy = {
|
|
148
|
+
assigned: manifest.skillPolicy?.assigned ?? [],
|
|
149
|
+
allowTenantSkills: manifest.skillPolicy?.allowTenantSkills ?? false,
|
|
150
|
+
};
|
|
151
|
+
const skillLoader = config.skills === undefined ? undefined : createSkillBodyLoader({ resolver: config.skills, policy: skillPolicy });
|
|
152
|
+
const toolRegistry = createToolRegistry({
|
|
153
|
+
providers: config.tools ?? [],
|
|
154
|
+
authorization,
|
|
155
|
+
...(config.toolSearch === undefined ? {} : { search: config.toolSearch }),
|
|
156
|
+
...(config.toolsets === undefined ? {} : { toolsets: config.toolsets }),
|
|
157
|
+
...(config.catalogBudget === undefined ? {} : { catalogBudget: config.catalogBudget }),
|
|
158
|
+
...(skillLoader === undefined ? {} : { skills: skillLoader }),
|
|
159
|
+
...(config.shadow === undefined ? {} : { shadow: config.shadow }),
|
|
160
|
+
});
|
|
60
161
|
const resolveModel = config.resolveModel ??
|
|
61
162
|
((m) => {
|
|
62
163
|
const def = registry.resolve(m.modelPolicy);
|
|
@@ -64,11 +165,25 @@ export const createAgent = (config) => {
|
|
|
64
165
|
model: providerFactory.languageModel(def),
|
|
65
166
|
modelId: def.modelId,
|
|
66
167
|
currency: def.pricing.currency,
|
|
67
|
-
price: (u) => computeModelCostMinorUnits(def.pricing, {
|
|
168
|
+
price: (u) => computeModelCostMinorUnits(def.pricing, {
|
|
169
|
+
inputTokens: u.inputTokens,
|
|
170
|
+
outputTokens: u.outputTokens,
|
|
171
|
+
cachedInputTokens: u.cachedInputTokens,
|
|
172
|
+
// Dropped here before #247, so a cache write was billed as fresh input — and on a provider that
|
|
173
|
+
// charges a premium for a write, under-billed.
|
|
174
|
+
...(u.cacheWriteTokens === undefined ? {} : { cacheWriteTokens: u.cacheWriteTokens }),
|
|
175
|
+
}),
|
|
68
176
|
};
|
|
69
177
|
});
|
|
70
|
-
const contextProviders =
|
|
178
|
+
const contextProviders = [
|
|
179
|
+
...(config.contextProviders ?? []),
|
|
180
|
+
...(config.skills === undefined
|
|
181
|
+
? []
|
|
182
|
+
: [createSkillCatalogueProvider({ resolver: config.skills, policy: skillPolicy })]),
|
|
183
|
+
];
|
|
71
184
|
const engine = config.engine ?? createDefaultEngine({
|
|
185
|
+
...(config.guardrails === undefined ? {} : { guardrails: config.guardrails }),
|
|
186
|
+
...(config.catalogBudget === undefined ? {} : { catalogBudget: config.catalogBudget }),
|
|
72
187
|
async loadManifest() {
|
|
73
188
|
return manifest; // single-manifest embedded agent
|
|
74
189
|
},
|
|
@@ -88,7 +203,7 @@ export const createAgent = (config) => {
|
|
|
88
203
|
* assembly, so content cannot learn the delimiter from a previous turn.
|
|
89
204
|
*/
|
|
90
205
|
systemPrompt: async (m, context) => {
|
|
91
|
-
const sections = await gatherSections(context, contextProviders);
|
|
206
|
+
const sections = await gatherSections(context, selectContextProviders(contextProviders, m));
|
|
92
207
|
if (sections.length === 0)
|
|
93
208
|
return m.instructions;
|
|
94
209
|
const ctxText = renderContextBlock(sections, makeNonce(config.randomHex ?? defaultRandomHex));
|
|
@@ -120,19 +235,100 @@ export const createAgent = (config) => {
|
|
|
120
235
|
},
|
|
121
236
|
...(config.tools && config.tools.length > 0
|
|
122
237
|
? {
|
|
238
|
+
/**
|
|
239
|
+
* The tools this turn, through the registry rather than around it — task #210.
|
|
240
|
+
*
|
|
241
|
+
* This used to gather the providers itself and filter them with `authorization.filterTools`, which was
|
|
242
|
+
* a second copy of what the registry does: no duplicate-name check, and — once tenant toolsets existed
|
|
243
|
+
* — no toolset either, so a switched-off category was hidden everywhere except in the list actually
|
|
244
|
+
* handed to the model.
|
|
245
|
+
*/
|
|
123
246
|
buildTools: async (context) => {
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
247
|
+
const descriptors = await toolRegistry.listAuthorized(context);
|
|
248
|
+
const resolvedTools = descriptors.map((descriptor) => ({
|
|
249
|
+
name: descriptor.name,
|
|
250
|
+
description: descriptor.description,
|
|
251
|
+
// Carried through so the engine can honour `toolPolicy.categories` without reaching back into
|
|
252
|
+
// the registry for a descriptor it already handed over — #244.
|
|
253
|
+
category: descriptor.category,
|
|
254
|
+
inputSchema: descriptor.inputSchema,
|
|
255
|
+
execute: async (input) => {
|
|
256
|
+
const result = await toolRegistry.execute(context, { name: descriptor.name, input });
|
|
257
|
+
if (!result.ok)
|
|
258
|
+
throw new AgentPlatformError(result.error);
|
|
259
|
+
return result.data;
|
|
260
|
+
},
|
|
261
|
+
}));
|
|
262
|
+
/**
|
|
263
|
+
* `find_tools`, when a search is wired — task #210, AC-1.
|
|
264
|
+
*
|
|
265
|
+
* Its schema is written here because a meta-tool descriptor carries none, and a model handed a
|
|
266
|
+
* permissive schema streams `{}` for every call. The registry validates the arguments itself.
|
|
267
|
+
*/
|
|
268
|
+
/**
|
|
269
|
+
* `execute_tool`, alongside search — task #210.
|
|
270
|
+
*
|
|
271
|
+
* Without it `find_tools` is a dead end: the tool it names is not in this turn's list (that is why
|
|
272
|
+
* it had to be searched for), so the model learns a name it cannot call. Added whenever search or a
|
|
273
|
+
* budget is configured, which are exactly the cases where the list is partial.
|
|
274
|
+
*/
|
|
275
|
+
if (config.toolSearch !== undefined || config.catalogBudget !== undefined) {
|
|
276
|
+
resolvedTools.push({
|
|
277
|
+
name: "execute_tool",
|
|
278
|
+
description: "Run a tool by name — including one that is not listed here, for example one you found with " +
|
|
279
|
+
"find_tools. Authorization and approval apply exactly as they would to a direct call.",
|
|
280
|
+
inputSchema: {
|
|
281
|
+
type: "object",
|
|
282
|
+
properties: {
|
|
283
|
+
name: { type: "string", description: "The tool's name." },
|
|
284
|
+
input: { type: "object", description: "The tool's arguments, matching its schema." },
|
|
285
|
+
},
|
|
286
|
+
required: ["name", "input"],
|
|
287
|
+
},
|
|
288
|
+
execute: async (input, options) => {
|
|
289
|
+
const result = await toolRegistry.execute(context, { name: "execute_tool", input });
|
|
290
|
+
// What actually ran, so the run event log names the action rather than the mechanism.
|
|
291
|
+
if (result.ranToolName !== undefined)
|
|
292
|
+
options?.report?.({ ranToolName: result.ranToolName });
|
|
293
|
+
if (!result.ok)
|
|
294
|
+
throw new AgentPlatformError(result.error);
|
|
295
|
+
return result.data;
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
if (config.toolSearch !== undefined || config.catalogBudget !== undefined) {
|
|
130
300
|
resolvedTools.push({
|
|
131
|
-
name:
|
|
132
|
-
description:
|
|
133
|
-
|
|
301
|
+
name: "learn_tools",
|
|
302
|
+
description: "Fetch the full input schemas for tools by name — including ones not listed here. Call this " +
|
|
303
|
+
"before running a tool you found with find_tools, so you know what arguments it takes.",
|
|
304
|
+
inputSchema: {
|
|
305
|
+
type: "object",
|
|
306
|
+
properties: { names: { type: "array", items: { type: "string" } } },
|
|
307
|
+
required: ["names"],
|
|
308
|
+
},
|
|
309
|
+
execute: async (input) => {
|
|
310
|
+
const result = await toolRegistry.execute(context, { name: "learn_tools", input });
|
|
311
|
+
if (!result.ok)
|
|
312
|
+
throw new AgentPlatformError(result.error);
|
|
313
|
+
return result.data;
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
if (config.toolSearch !== undefined) {
|
|
318
|
+
resolvedTools.push({
|
|
319
|
+
name: "find_tools",
|
|
320
|
+
description: "Search for a tool by describing what you need to do. Not all available tools are listed, so " +
|
|
321
|
+
"search before concluding that something cannot be done. Run what you find with execute_tool.",
|
|
322
|
+
inputSchema: {
|
|
323
|
+
type: "object",
|
|
324
|
+
properties: {
|
|
325
|
+
query: { type: "string", description: "What you are trying to do, in your own words." },
|
|
326
|
+
limit: { type: "number", description: "How many tools to return. Default 10." },
|
|
327
|
+
},
|
|
328
|
+
required: ["query"],
|
|
329
|
+
},
|
|
134
330
|
execute: async (input) => {
|
|
135
|
-
const result = await toolRegistry.execute(context, { name:
|
|
331
|
+
const result = await toolRegistry.execute(context, { name: "find_tools", input });
|
|
136
332
|
if (!result.ok)
|
|
137
333
|
throw new AgentPlatformError(result.error);
|
|
138
334
|
return result.data;
|
|
@@ -173,6 +369,9 @@ export const createAgent = (config) => {
|
|
|
173
369
|
requestId: asId(`req-${seq}`),
|
|
174
370
|
conversationId,
|
|
175
371
|
runId,
|
|
372
|
+
// Only when asked. Defaulting to shadow would make every existing run a shadow run; the dangerous
|
|
373
|
+
// direction — claiming shadow with nowhere to record it — is closed in the registry instead.
|
|
374
|
+
...(input.shadow === true ? { shadow: true } : {}),
|
|
176
375
|
};
|
|
177
376
|
contextByRun.set(runId, context);
|
|
178
377
|
if (!(await conversations.findById({ tenantId, id: conversationId }))) {
|
package/dist/agents/define.js
CHANGED
|
@@ -39,9 +39,22 @@ export const DEFAULT_MODEL_CATALOG = [
|
|
|
39
39
|
label: "Claude Sonnet 5",
|
|
40
40
|
lifecycle: "generally-available",
|
|
41
41
|
inputModalities: ["text", "image"],
|
|
42
|
-
capabilities: { tools: true, structuredOutput: true, reasoning: true, nativeSearch: false },
|
|
42
|
+
capabilities: { tools: true, structuredOutput: true, reasoning: true, nativeSearch: false, promptCaching: "explicit" },
|
|
43
43
|
limits: { contextTokens: 200_000, maxOutputTokens: 8_192 },
|
|
44
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Cache rates, added by #247.
|
|
46
|
+
*
|
|
47
|
+
* Anthropic's published ratios: a cache **read** is 0.1× a fresh input token and a cache **write** is
|
|
48
|
+
* **1.25×** — a write costs *more*. `cacheWritePerMillion` was in `ModelPricing` and read by nothing, so a
|
|
49
|
+
* cache write was billed as ordinary input and the first turn of every conversation was under-billed.
|
|
50
|
+
*/
|
|
51
|
+
pricing: {
|
|
52
|
+
currency: "USD",
|
|
53
|
+
inputPerMillion: 3_000,
|
|
54
|
+
outputPerMillion: 15_000,
|
|
55
|
+
cacheReadPerMillion: 300,
|
|
56
|
+
cacheWritePerMillion: 3_750,
|
|
57
|
+
},
|
|
45
58
|
dataResidency: ["us"],
|
|
46
59
|
},
|
|
47
60
|
{
|
|
@@ -50,9 +63,16 @@ export const DEFAULT_MODEL_CATALOG = [
|
|
|
50
63
|
label: "Claude Haiku 4.5",
|
|
51
64
|
lifecycle: "generally-available",
|
|
52
65
|
inputModalities: ["text", "image"],
|
|
53
|
-
capabilities: { tools: true, structuredOutput: true, reasoning: false, nativeSearch: false },
|
|
66
|
+
capabilities: { tools: true, structuredOutput: true, reasoning: false, nativeSearch: false, promptCaching: "explicit" },
|
|
54
67
|
limits: { contextTokens: 200_000, maxOutputTokens: 8_192 },
|
|
55
|
-
pricing: {
|
|
68
|
+
pricing: {
|
|
69
|
+
currency: "USD",
|
|
70
|
+
inputPerMillion: 800,
|
|
71
|
+
outputPerMillion: 4_000,
|
|
72
|
+
// Same ratios as Sonnet above: read 0.1×, write 1.25×.
|
|
73
|
+
cacheReadPerMillion: 80,
|
|
74
|
+
cacheWritePerMillion: 1_000,
|
|
75
|
+
},
|
|
56
76
|
dataResidency: ["us"],
|
|
57
77
|
},
|
|
58
78
|
];
|
package/dist/agents/engine.d.ts
CHANGED
|
@@ -18,12 +18,23 @@
|
|
|
18
18
|
* on a refusal the model cannot resolve.
|
|
19
19
|
*/
|
|
20
20
|
import type { ExecutionContext } from "../core/context.js";
|
|
21
|
+
import { type ConnectionNeed } from "../connections/pause.js";
|
|
21
22
|
import type { RunId, TenantId } from "../core/ids.js";
|
|
22
23
|
import type { ModelDefinition, ModelTurnRequest, ModelTurnTool, NeutralStreamChunk, NeutralUsage, ResolvedModel, TurnMessage } from "../models/index.js";
|
|
24
|
+
import { type Guardrail } from "../guardrails/index.js";
|
|
23
25
|
import { type AgentEngine, type RetryPolicy, type Run } from "../runtime/index.js";
|
|
26
|
+
import { type TokenBudget } from "../core/budget.js";
|
|
24
27
|
import type { PendingQuestion, RunApprovals } from "../hitl/index.js";
|
|
25
28
|
import type { CitationEmitter } from "../citations/index.js";
|
|
26
29
|
import type { AgentManifest } from "./index.js";
|
|
30
|
+
/**
|
|
31
|
+
* What one tool costs the model's context.
|
|
32
|
+
*
|
|
33
|
+
* A `ModelTurnTool` is not a catalogue entry — it carries the full input schema, because that is what a provider
|
|
34
|
+
* puts in the request — so this deliberately does *not* reuse `entryTokens`. Using the compact estimate here
|
|
35
|
+
* would understate a schema-heavy tool by an order of magnitude and produce a budget that never binds.
|
|
36
|
+
*/
|
|
37
|
+
export declare const turnToolTokens: (tool: ModelTurnTool) => number;
|
|
27
38
|
/** A model resolved for a turn: the opaque handle plus what the engine needs to attribute usage. */
|
|
28
39
|
export type ResolvedModelInfo = {
|
|
29
40
|
readonly model: ResolvedModel;
|
|
@@ -63,6 +74,24 @@ export type DefaultEngineDeps = {
|
|
|
63
74
|
* pause on.
|
|
64
75
|
*/
|
|
65
76
|
readonly approvals?: RunApprovals;
|
|
77
|
+
/**
|
|
78
|
+
* Checks a deployment adds — REQ-046 (#205).
|
|
79
|
+
*
|
|
80
|
+
* Absent means no inspection, which is the current behaviour and stays the default: a runtime that imposed a
|
|
81
|
+
* model call on every turn to moderate it would be making a cost decision that belongs to the host.
|
|
82
|
+
*/
|
|
83
|
+
readonly guardrails?: readonly Guardrail[];
|
|
84
|
+
/**
|
|
85
|
+
* A ceiling in tokens on the tool list handed to the model — REQ-045 (#204), task #210, AC-3.
|
|
86
|
+
*
|
|
87
|
+
* Here rather than only in the registry because *this* is where the tokens are actually spent: the registry's
|
|
88
|
+
* catalogue is what a client renders, and `buildTools` is what reaches the provider. A budget enforced in one
|
|
89
|
+
* and not the other would be a budget a deployment believes it has.
|
|
90
|
+
*
|
|
91
|
+
* Absent means no ceiling, which stays the default — a runtime that silently withheld tools from a model
|
|
92
|
+
* nobody had asked it to withhold would be making a correctness decision on the host's behalf.
|
|
93
|
+
*/
|
|
94
|
+
readonly catalogBudget?: TokenBudget;
|
|
66
95
|
/**
|
|
67
96
|
* The question side of resumption — #163.
|
|
68
97
|
*
|
|
@@ -93,6 +122,25 @@ export type DefaultEngineDeps = {
|
|
|
93
122
|
readonly now?: () => number;
|
|
94
123
|
/** The streaming primitive. Defaults to the models-layer `streamModelTurn`; overridden in tests. */
|
|
95
124
|
readonly streamTurn?: (req: ModelTurnRequest) => AsyncIterable<NeutralStreamChunk>;
|
|
125
|
+
/**
|
|
126
|
+
* Turns "this run needs a connection" into somewhere to send a person — task #264.
|
|
127
|
+
*
|
|
128
|
+
* **Optional, and its absence means today's behaviour**: the tool call fails and the run fails with it. That
|
|
129
|
+
* is the correct default, not a degraded one — a host with no OAuth flow wired has no login URL to offer, and
|
|
130
|
+
* pausing a run for a consent screen nobody can reach would hang it for ever.
|
|
131
|
+
*
|
|
132
|
+
* Returning `null` says the same thing for one provider: this one is token-only, so fail rather than pause.
|
|
133
|
+
* That decision comes from `ToolkitAuth.modes`, which is why #260 kept `AuthMode` separate from
|
|
134
|
+
* `CredentialScheme` — an OAuth token is presented as a bearer, so the wire format cannot answer it.
|
|
135
|
+
*/
|
|
136
|
+
readonly connectionConsent?: (input: {
|
|
137
|
+
readonly context: ExecutionContext;
|
|
138
|
+
readonly need: ConnectionNeed;
|
|
139
|
+
}) => Promise<{
|
|
140
|
+
readonly loginUrl: string;
|
|
141
|
+
readonly scopes: readonly string[];
|
|
142
|
+
readonly expiresAt: string;
|
|
143
|
+
} | null>;
|
|
96
144
|
};
|
|
97
145
|
export declare const createDefaultEngine: (deps: DefaultEngineDeps) => AgentEngine;
|
|
98
146
|
//# sourceMappingURL=engine.d.ts.map
|