@retinue/agentkit 0.2.0 → 0.3.1
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 +1 -1
- 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/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 +78 -1
- package/dist/agents/agent.js +118 -5
- package/dist/agents/define.js +24 -4
- package/dist/agents/engine.d.ts +20 -0
- package/dist/agents/engine.js +177 -6
- package/dist/audio/index.d.ts +151 -0
- package/dist/audio/index.js +183 -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/content-parts.d.ts +18 -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 +44 -2
- package/dist/core/events.js +31 -2
- package/dist/core/validation.js +19 -0
- package/dist/entries/connections.d.ts +10 -0
- package/dist/entries/connections.js +10 -0
- package/dist/entries/knowledge.d.ts +8 -0
- package/dist/entries/knowledge.js +8 -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 +3 -1
- package/dist/graphql/resolvers.js +14 -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 +24 -0
- package/dist/knowledge/index.js +36 -1
- package/dist/knowledge/retrieval.d.ts +26 -1
- package/dist/knowledge/retrieval.js +77 -1
- 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 +89 -0
- package/dist/models/streaming.js +179 -2
- 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 +46 -0
- package/dist/server/bin.d.ts +72 -0
- package/dist/server/bin.js +304 -0
- package/dist/server/boot.d.ts +20 -2
- package/dist/server/boot.js +29 -3
- package/dist/server/cli-worker.js +6 -3
- package/dist/server/cli.d.ts +13 -0
- package/dist/server/cli.js +10 -5
- package/dist/server/config.d.ts +11 -1
- package/dist/server/config.js +18 -0
- package/dist/server/doctor.d.ts +85 -0
- package/dist/server/doctor.js +280 -0
- package/dist/server/pool.d.ts +47 -0
- package/dist/server/pool.js +73 -0
- package/dist/skills/context.d.ts +61 -0
- package/dist/skills/context.js +107 -0
- package/dist/skills/index.d.ts +1 -0
- package/dist/skills/index.js +1 -0
- package/dist/telemetry/spans.js +5 -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/http.d.ts +27 -0
- package/dist/toolkit/http.js +48 -0
- package/dist/toolkit/index.d.ts +27 -1
- package/dist/toolkit/index.js +24 -1
- package/dist/toolkit/mime.d.ts +97 -0
- package/dist/toolkit/mime.js +233 -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/tools/credentials.d.ts +265 -6
- package/dist/tools/credentials.js +318 -3
- package/dist/tools/define.d.ts +14 -0
- package/dist/tools/define.js +3 -0
- package/dist/tools/index.d.ts +21 -0
- package/dist/tools/index.js +7 -0
- package/dist/tools/library/audio.d.ts +63 -0
- package/dist/tools/library/audio.js +148 -0
- package/dist/tools/library/index.d.ts +8 -0
- package/dist/tools/library/index.js +7 -0
- package/dist/tools/registry.d.ts +33 -0
- package/dist/tools/registry.js +72 -2
- 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 +29 -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,13 +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, type ToolSearch, type ToolsetResolver } from "../tools/index.js";
|
|
18
|
+
import { type ShadowRecorder, type ToolProvider, type ToolSearch, type ToolsetResolver } from "../tools/index.js";
|
|
19
19
|
import type { TokenBudget } from "../core/budget.js";
|
|
20
20
|
import { type AgentEngine, type ProcessOutcome } from "../runtime/index.js";
|
|
21
21
|
import type { Guardrail } from "../guardrails/index.js";
|
|
22
|
+
import { type SkillResolver } from "../skills/index.js";
|
|
22
23
|
import { type ResolvedModelInfo } from "./engine.js";
|
|
23
24
|
import type { AgentManifest } from "./index.js";
|
|
24
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[];
|
|
25
64
|
export type CreateAgentConfig = {
|
|
26
65
|
readonly manifest: AgentManifestInput;
|
|
27
66
|
/** Model catalog; defaults to a small Anthropic catalog (smart/fast). */
|
|
@@ -40,6 +79,15 @@ export type CreateAgentConfig = {
|
|
|
40
79
|
*/
|
|
41
80
|
readonly randomHex?: (bytes: number) => string;
|
|
42
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>>;
|
|
43
91
|
/**
|
|
44
92
|
* Checks to run before the model sees a turn and before anything leaves it — REQ-046 (#205), AC-5.
|
|
45
93
|
*
|
|
@@ -59,7 +107,24 @@ export type CreateAgentConfig = {
|
|
|
59
107
|
readonly catalogBudget?: TokenBudget;
|
|
60
108
|
/** A tenant's category switches, applied before authorization — task #210, AC-4. */
|
|
61
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;
|
|
62
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;
|
|
63
128
|
/** Test/advanced seam: override how a manifest resolves to a model (e.g. a mock model). */
|
|
64
129
|
readonly resolveModel?: (manifest: AgentManifest, context: ExecutionContext) => ResolvedModelInfo;
|
|
65
130
|
/** Test/advanced seam: supply the engine directly instead of building the default one. */
|
|
@@ -71,6 +136,18 @@ export type RunInput = {
|
|
|
71
136
|
readonly message: string;
|
|
72
137
|
readonly principalId?: string;
|
|
73
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;
|
|
74
151
|
};
|
|
75
152
|
export type RunResult = {
|
|
76
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,13 +136,27 @@ 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
|
|
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 });
|
|
59
152
|
const toolRegistry = createToolRegistry({
|
|
60
153
|
providers: config.tools ?? [],
|
|
61
154
|
authorization,
|
|
62
155
|
...(config.toolSearch === undefined ? {} : { search: config.toolSearch }),
|
|
63
156
|
...(config.toolsets === undefined ? {} : { toolsets: config.toolsets }),
|
|
64
157
|
...(config.catalogBudget === undefined ? {} : { catalogBudget: config.catalogBudget }),
|
|
158
|
+
...(skillLoader === undefined ? {} : { skills: skillLoader }),
|
|
159
|
+
...(config.shadow === undefined ? {} : { shadow: config.shadow }),
|
|
65
160
|
});
|
|
66
161
|
const resolveModel = config.resolveModel ??
|
|
67
162
|
((m) => {
|
|
@@ -70,10 +165,22 @@ export const createAgent = (config) => {
|
|
|
70
165
|
model: providerFactory.languageModel(def),
|
|
71
166
|
modelId: def.modelId,
|
|
72
167
|
currency: def.pricing.currency,
|
|
73
|
-
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
|
+
}),
|
|
74
176
|
};
|
|
75
177
|
});
|
|
76
|
-
const contextProviders =
|
|
178
|
+
const contextProviders = [
|
|
179
|
+
...(config.contextProviders ?? []),
|
|
180
|
+
...(config.skills === undefined
|
|
181
|
+
? []
|
|
182
|
+
: [createSkillCatalogueProvider({ resolver: config.skills, policy: skillPolicy })]),
|
|
183
|
+
];
|
|
77
184
|
const engine = config.engine ?? createDefaultEngine({
|
|
78
185
|
...(config.guardrails === undefined ? {} : { guardrails: config.guardrails }),
|
|
79
186
|
...(config.catalogBudget === undefined ? {} : { catalogBudget: config.catalogBudget }),
|
|
@@ -96,7 +203,7 @@ export const createAgent = (config) => {
|
|
|
96
203
|
* assembly, so content cannot learn the delimiter from a previous turn.
|
|
97
204
|
*/
|
|
98
205
|
systemPrompt: async (m, context) => {
|
|
99
|
-
const sections = await gatherSections(context, contextProviders);
|
|
206
|
+
const sections = await gatherSections(context, selectContextProviders(contextProviders, m));
|
|
100
207
|
if (sections.length === 0)
|
|
101
208
|
return m.instructions;
|
|
102
209
|
const ctxText = renderContextBlock(sections, makeNonce(config.randomHex ?? defaultRandomHex));
|
|
@@ -141,6 +248,9 @@ export const createAgent = (config) => {
|
|
|
141
248
|
const resolvedTools = descriptors.map((descriptor) => ({
|
|
142
249
|
name: descriptor.name,
|
|
143
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,
|
|
144
254
|
inputSchema: descriptor.inputSchema,
|
|
145
255
|
execute: async (input) => {
|
|
146
256
|
const result = await toolRegistry.execute(context, { name: descriptor.name, input });
|
|
@@ -259,6 +369,9 @@ export const createAgent = (config) => {
|
|
|
259
369
|
requestId: asId(`req-${seq}`),
|
|
260
370
|
conversationId,
|
|
261
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 } : {}),
|
|
262
375
|
};
|
|
263
376
|
contextByRun.set(runId, context);
|
|
264
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,6 +18,7 @@
|
|
|
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";
|
|
23
24
|
import { type Guardrail } from "../guardrails/index.js";
|
|
@@ -121,6 +122,25 @@ export type DefaultEngineDeps = {
|
|
|
121
122
|
readonly now?: () => number;
|
|
122
123
|
/** The streaming primitive. Defaults to the models-layer `streamModelTurn`; overridden in tests. */
|
|
123
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>;
|
|
124
144
|
};
|
|
125
145
|
export declare const createDefaultEngine: (deps: DefaultEngineDeps) => AgentEngine;
|
|
126
146
|
//# sourceMappingURL=engine.d.ts.map
|