@retinue/agentkit 0.1.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/LICENSE +22 -0
- package/README.md +310 -0
- package/dist/adapters/bullmq/consumer.d.ts +33 -0
- package/dist/adapters/bullmq/consumer.js +41 -0
- package/dist/adapters/bullmq/dispatcher.d.ts +74 -0
- package/dist/adapters/bullmq/dispatcher.js +160 -0
- package/dist/adapters/bullmq/export.d.ts +31 -0
- package/dist/adapters/bullmq/export.js +53 -0
- package/dist/adapters/bullmq/extraction.d.ts +42 -0
- package/dist/adapters/bullmq/extraction.js +63 -0
- package/dist/adapters/bullmq/index.d.ts +13 -0
- package/dist/adapters/bullmq/index.js +13 -0
- package/dist/adapters/bullmq/lock.d.ts +77 -0
- package/dist/adapters/bullmq/lock.js +126 -0
- package/dist/adapters/bullmq/queue.d.ts +50 -0
- package/dist/adapters/bullmq/queue.js +81 -0
- package/dist/adapters/memory/artifact-exports.d.ts +11 -0
- package/dist/adapters/memory/artifact-exports.js +102 -0
- package/dist/adapters/memory/artifacts.d.ts +15 -0
- package/dist/adapters/memory/artifacts.js +134 -0
- package/dist/adapters/memory/blobs.d.ts +7 -0
- package/dist/adapters/memory/blobs.js +27 -0
- package/dist/adapters/memory/evaluation.d.ts +18 -0
- package/dist/adapters/memory/evaluation.js +148 -0
- package/dist/adapters/memory/files.d.ts +27 -0
- package/dist/adapters/memory/files.js +0 -0
- package/dist/adapters/memory/flows.d.ts +16 -0
- package/dist/adapters/memory/flows.js +117 -0
- package/dist/adapters/memory/hitl.d.ts +9 -0
- package/dist/adapters/memory/hitl.js +130 -0
- package/dist/adapters/memory/idempotency.d.ts +13 -0
- package/dist/adapters/memory/idempotency.js +32 -0
- package/dist/adapters/memory/index.d.ts +39 -0
- package/dist/adapters/memory/index.js +107 -0
- package/dist/adapters/memory/knowledge.d.ts +43 -0
- package/dist/adapters/memory/knowledge.js +248 -0
- package/dist/adapters/memory/mcp.d.ts +9 -0
- package/dist/adapters/memory/mcp.js +37 -0
- package/dist/adapters/memory/message-store.d.ts +17 -0
- package/dist/adapters/memory/message-store.js +70 -0
- package/dist/adapters/memory/principal-memory.d.ts +7 -0
- package/dist/adapters/memory/principal-memory.js +83 -0
- package/dist/adapters/memory/runtime.d.ts +29 -0
- package/dist/adapters/memory/runtime.js +0 -0
- package/dist/adapters/memory/sessions.d.ts +29 -0
- package/dist/adapters/memory/sessions.js +0 -0
- package/dist/adapters/memory/skills.d.ts +10 -0
- package/dist/adapters/memory/skills.js +41 -0
- package/dist/adapters/memory/thread-summary.d.ts +7 -0
- package/dist/adapters/memory/thread-summary.js +29 -0
- package/dist/adapters/memory/usage-limits.d.ts +13 -0
- package/dist/adapters/memory/usage-limits.js +72 -0
- package/dist/adapters/memory/usage.d.ts +16 -0
- package/dist/adapters/memory/usage.js +279 -0
- package/dist/adapters/otel/index.d.ts +111 -0
- package/dist/adapters/otel/index.js +133 -0
- package/dist/adapters/postgres/artifact-exports.d.ts +12 -0
- package/dist/adapters/postgres/artifact-exports.js +117 -0
- package/dist/adapters/postgres/artifacts.d.ts +16 -0
- package/dist/adapters/postgres/artifacts.js +172 -0
- package/dist/adapters/postgres/checkpoint-store.d.ts +16 -0
- package/dist/adapters/postgres/checkpoint-store.js +34 -0
- package/dist/adapters/postgres/config.d.ts +15 -0
- package/dist/adapters/postgres/config.js +187 -0
- package/dist/adapters/postgres/conversation-store.d.ts +4 -0
- package/dist/adapters/postgres/conversation-store.js +82 -0
- package/dist/adapters/postgres/evaluation.d.ts +17 -0
- package/dist/adapters/postgres/evaluation.js +193 -0
- package/dist/adapters/postgres/file-content.d.ts +30 -0
- package/dist/adapters/postgres/file-content.js +111 -0
- package/dist/adapters/postgres/files.d.ts +19 -0
- package/dist/adapters/postgres/files.js +209 -0
- package/dist/adapters/postgres/flows.d.ts +20 -0
- package/dist/adapters/postgres/flows.js +206 -0
- package/dist/adapters/postgres/hitl.d.ts +5 -0
- package/dist/adapters/postgres/hitl.js +247 -0
- package/dist/adapters/postgres/index.d.ts +35 -0
- package/dist/adapters/postgres/index.js +35 -0
- package/dist/adapters/postgres/knowledge.d.ts +48 -0
- package/dist/adapters/postgres/knowledge.js +255 -0
- package/dist/adapters/postgres/memory.d.ts +14 -0
- package/dist/adapters/postgres/memory.js +194 -0
- package/dist/adapters/postgres/message-store.d.ts +11 -0
- package/dist/adapters/postgres/message-store.js +145 -0
- package/dist/adapters/postgres/migrations.d.ts +69 -0
- package/dist/adapters/postgres/migrations.js +1594 -0
- package/dist/adapters/postgres/pg-executor.d.ts +19 -0
- package/dist/adapters/postgres/pg-executor.js +32 -0
- package/dist/adapters/postgres/retention.d.ts +26 -0
- package/dist/adapters/postgres/retention.js +59 -0
- package/dist/adapters/postgres/rollups.d.ts +17 -0
- package/dist/adapters/postgres/rollups.js +267 -0
- package/dist/adapters/postgres/run-coordinator.d.ts +5 -0
- package/dist/adapters/postgres/run-coordinator.js +98 -0
- package/dist/adapters/postgres/run-event-log.d.ts +26 -0
- package/dist/adapters/postgres/run-event-log.js +30 -0
- package/dist/adapters/postgres/run-store.d.ts +4 -0
- package/dist/adapters/postgres/run-store.js +199 -0
- package/dist/adapters/postgres/schema.d.ts +39 -0
- package/dist/adapters/postgres/schema.js +70 -0
- package/dist/adapters/postgres/session-state.d.ts +7 -0
- package/dist/adapters/postgres/session-state.js +99 -0
- package/dist/adapters/postgres/sql.d.ts +8 -0
- package/dist/adapters/postgres/sql.js +2 -0
- package/dist/adapters/postgres/transaction.d.ts +37 -0
- package/dist/adapters/postgres/transaction.js +93 -0
- package/dist/adapters/postgres/unit-of-work.d.ts +18 -0
- package/dist/adapters/postgres/unit-of-work.js +8 -0
- package/dist/adapters/postgres/usage-limits.d.ts +15 -0
- package/dist/adapters/postgres/usage-limits.js +136 -0
- package/dist/adapters/postgres/usage.d.ts +15 -0
- package/dist/adapters/postgres/usage.js +226 -0
- package/dist/adapters/redis/index.d.ts +9 -0
- package/dist/adapters/redis/index.js +9 -0
- package/dist/adapters/redis/realtime.d.ts +74 -0
- package/dist/adapters/redis/realtime.js +112 -0
- package/dist/adapters/supabase/index.d.ts +88 -0
- package/dist/adapters/supabase/index.js +84 -0
- package/dist/adapters/supabase/realtime.d.ts +30 -0
- package/dist/adapters/supabase/realtime.js +53 -0
- package/dist/adapters/supabase/rls.d.ts +99 -0
- package/dist/adapters/supabase/rls.js +216 -0
- package/dist/adapters/supabase/storage.d.ts +50 -0
- package/dist/adapters/supabase/storage.js +207 -0
- package/dist/agents/agent.d.ts +66 -0
- package/dist/agents/agent.js +209 -0
- package/dist/agents/define.d.ts +21 -0
- package/dist/agents/define.js +63 -0
- package/dist/agents/engine.d.ts +98 -0
- package/dist/agents/engine.js +462 -0
- package/dist/agents/index.d.ts +50 -0
- package/dist/agents/index.js +17 -0
- package/dist/artifacts/index.d.ts +114 -0
- package/dist/artifacts/index.js +219 -0
- package/dist/authorization/index.d.ts +76 -0
- package/dist/authorization/index.js +76 -0
- package/dist/capabilities/index.d.ts +120 -0
- package/dist/capabilities/index.js +167 -0
- package/dist/capabilities/runtime.d.ts +89 -0
- package/dist/capabilities/runtime.js +84 -0
- package/dist/citations/index.d.ts +161 -0
- package/dist/citations/index.js +182 -0
- package/dist/context/assembler.d.ts +82 -0
- package/dist/context/assembler.js +129 -0
- package/dist/context/compaction.d.ts +45 -0
- package/dist/context/compaction.js +55 -0
- package/dist/context/index.d.ts +75 -0
- package/dist/context/index.js +17 -0
- package/dist/core/content-parts.d.ts +194 -0
- package/dist/core/content-parts.js +23 -0
- package/dist/core/context.d.ts +51 -0
- package/dist/core/context.js +9 -0
- package/dist/core/env.d.ts +25 -0
- package/dist/core/env.js +41 -0
- package/dist/core/errors.d.ts +30 -0
- package/dist/core/errors.js +65 -0
- package/dist/core/events.d.ts +139 -0
- package/dist/core/events.js +99 -0
- package/dist/core/ids.d.ts +52 -0
- package/dist/core/ids.js +13 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.js +9 -0
- package/dist/core/tokens.d.ts +22 -0
- package/dist/core/tokens.js +22 -0
- package/dist/core/validation.d.ts +34 -0
- package/dist/core/validation.js +176 -0
- package/dist/documents/extraction.d.ts +121 -0
- package/dist/documents/extraction.js +293 -0
- package/dist/documents/index.d.ts +199 -0
- package/dist/documents/index.js +65 -0
- package/dist/documents/parsers/pdf.d.ts +47 -0
- package/dist/documents/parsers/pdf.js +508 -0
- package/dist/documents/parsers/text.d.ts +59 -0
- package/dist/documents/parsers/text.js +325 -0
- package/dist/documents/read-tool.d.ts +52 -0
- package/dist/documents/read-tool.js +109 -0
- package/dist/documents/render.d.ts +29 -0
- package/dist/documents/render.js +59 -0
- package/dist/documents/vision.d.ts +159 -0
- package/dist/documents/vision.js +214 -0
- package/dist/entries/adapters-bullmq.d.ts +8 -0
- package/dist/entries/adapters-bullmq.js +8 -0
- package/dist/entries/adapters-otel.d.ts +13 -0
- package/dist/entries/adapters-otel.js +13 -0
- package/dist/entries/adapters-postgres.d.ts +10 -0
- package/dist/entries/adapters-postgres.js +10 -0
- package/dist/entries/adapters-redis.d.ts +3 -0
- package/dist/entries/adapters-redis.js +3 -0
- package/dist/entries/context.d.ts +20 -0
- package/dist/entries/context.js +20 -0
- package/dist/entries/flows.d.ts +15 -0
- package/dist/entries/flows.js +15 -0
- package/dist/entries/hitl.d.ts +10 -0
- package/dist/entries/hitl.js +10 -0
- package/dist/entries/knowledge.d.ts +18 -0
- package/dist/entries/knowledge.js +19 -0
- package/dist/entries/mcp.d.ts +10 -0
- package/dist/entries/mcp.js +10 -0
- package/dist/entries/observability.d.ts +14 -0
- package/dist/entries/observability.js +16 -0
- package/dist/entries/persistence.d.ts +11 -0
- package/dist/entries/persistence.js +11 -0
- package/dist/entries/providers.d.ts +14 -0
- package/dist/entries/providers.js +14 -0
- package/dist/entries/runtime.d.ts +13 -0
- package/dist/entries/runtime.js +13 -0
- package/dist/entries/server.d.ts +24 -0
- package/dist/entries/server.js +24 -0
- package/dist/entries/tools.d.ts +21 -0
- package/dist/entries/tools.js +21 -0
- package/dist/entries/usage.d.ts +10 -0
- package/dist/entries/usage.js +10 -0
- package/dist/evaluation/gate.d.ts +168 -0
- package/dist/evaluation/gate.js +180 -0
- package/dist/evaluation/graders.d.ts +125 -0
- package/dist/evaluation/graders.js +203 -0
- package/dist/evaluation/index.d.ts +120 -0
- package/dist/evaluation/index.js +183 -0
- package/dist/evaluation/judge.d.ts +75 -0
- package/dist/evaluation/judge.js +111 -0
- package/dist/export/index.d.ts +162 -0
- package/dist/export/index.js +363 -0
- package/dist/export/markdown.d.ts +19 -0
- package/dist/export/markdown.js +29 -0
- package/dist/export/pdf.d.ts +73 -0
- package/dist/export/pdf.js +407 -0
- package/dist/files/context.d.ts +97 -0
- package/dist/files/context.js +185 -0
- package/dist/files/index.d.ts +210 -0
- package/dist/files/index.js +338 -0
- package/dist/files/read-tool.d.ts +81 -0
- package/dist/files/read-tool.js +163 -0
- package/dist/files/turn-parts.d.ts +96 -0
- package/dist/files/turn-parts.js +171 -0
- package/dist/flows/index.d.ts +270 -0
- package/dist/flows/index.js +62 -0
- package/dist/flows/interpreter.d.ts +146 -0
- package/dist/flows/interpreter.js +426 -0
- package/dist/flows/runner.d.ts +145 -0
- package/dist/flows/runner.js +270 -0
- package/dist/graphql/index.d.ts +8 -0
- package/dist/graphql/index.js +8 -0
- package/dist/graphql/resolvers.d.ts +237 -0
- package/dist/graphql/resolvers.js +253 -0
- package/dist/graphql/schema.d.ts +11 -0
- package/dist/graphql/schema.js +258 -0
- package/dist/graphql/sse.d.ts +77 -0
- package/dist/graphql/sse.js +100 -0
- package/dist/hitl/approved-execution.d.ts +127 -0
- package/dist/hitl/approved-execution.js +177 -0
- package/dist/hitl/index.d.ts +79 -0
- package/dist/hitl/index.js +12 -0
- package/dist/hitl/service.d.ts +221 -0
- package/dist/hitl/service.js +268 -0
- package/dist/idempotency/index.d.ts +70 -0
- package/dist/idempotency/index.js +59 -0
- package/dist/index.d.ts +103 -0
- package/dist/index.js +60 -0
- package/dist/knowledge/chunking.d.ts +57 -0
- package/dist/knowledge/chunking.js +158 -0
- package/dist/knowledge/index.d.ts +119 -0
- package/dist/knowledge/index.js +166 -0
- package/dist/knowledge/retrieval.d.ts +146 -0
- package/dist/knowledge/retrieval.js +170 -0
- package/dist/loadtest/harness.d.ts +168 -0
- package/dist/loadtest/harness.js +507 -0
- package/dist/loadtest/index.d.ts +13 -0
- package/dist/loadtest/index.js +13 -0
- package/dist/loadtest/injection.d.ts +89 -0
- package/dist/loadtest/injection.js +147 -0
- package/dist/loadtest/metrics.d.ts +197 -0
- package/dist/loadtest/metrics.js +160 -0
- package/dist/loadtest/runbooks.d.ts +28 -0
- package/dist/loadtest/runbooks.js +159 -0
- package/dist/loadtest/scenario.d.ts +104 -0
- package/dist/loadtest/scenario.js +208 -0
- package/dist/mcp/egress.d.ts +53 -0
- package/dist/mcp/egress.js +115 -0
- package/dist/mcp/index.d.ts +93 -0
- package/dist/mcp/index.js +33 -0
- package/dist/mcp/provider.d.ts +62 -0
- package/dist/mcp/provider.js +0 -0
- package/dist/models/index.d.ts +98 -0
- package/dist/models/index.js +74 -0
- package/dist/models/pricing.d.ts +24 -0
- package/dist/models/pricing.js +37 -0
- package/dist/models/provider-factory.d.ts +31 -0
- package/dist/models/provider-factory.js +67 -0
- package/dist/models/streaming.d.ts +145 -0
- package/dist/models/streaming.js +272 -0
- package/dist/models/vision.d.ts +38 -0
- package/dist/models/vision.js +62 -0
- package/dist/persistence/index.d.ts +1654 -0
- package/dist/persistence/index.js +226 -0
- package/dist/principal-memory/index.d.ts +106 -0
- package/dist/principal-memory/index.js +89 -0
- package/dist/retention/index.d.ts +89 -0
- package/dist/retention/index.js +70 -0
- package/dist/runtime/checkpoint.d.ts +37 -0
- package/dist/runtime/checkpoint.js +22 -0
- package/dist/runtime/index.d.ts +118 -0
- package/dist/runtime/index.js +69 -0
- package/dist/runtime/retry.d.ts +95 -0
- package/dist/runtime/retry.js +126 -0
- package/dist/runtime/serialization.d.ts +85 -0
- package/dist/runtime/serialization.js +95 -0
- package/dist/runtime/streaming.d.ts +54 -0
- package/dist/runtime/streaming.js +115 -0
- package/dist/runtime/worker.d.ts +130 -0
- package/dist/runtime/worker.js +405 -0
- package/dist/security/checklist.d.ts +53 -0
- package/dist/security/checklist.js +204 -0
- package/dist/security/findings.d.ts +56 -0
- package/dist/security/findings.js +168 -0
- package/dist/security/index.d.ts +14 -0
- package/dist/security/index.js +14 -0
- package/dist/security/prompt-safety.d.ts +100 -0
- package/dist/security/prompt-safety.js +133 -0
- package/dist/server/boot.d.ts +32 -0
- package/dist/server/boot.js +36 -0
- package/dist/server/cli-worker.d.ts +37 -0
- package/dist/server/cli-worker.js +151 -0
- package/dist/server/cli.d.ts +27 -0
- package/dist/server/cli.js +74 -0
- package/dist/server/config.d.ts +42 -0
- package/dist/server/config.js +127 -0
- package/dist/server/health.d.ts +59 -0
- package/dist/server/health.js +90 -0
- package/dist/server/host.d.ts +39 -0
- package/dist/server/host.js +124 -0
- package/dist/server/index.d.ts +15 -0
- package/dist/server/index.js +15 -0
- package/dist/server/main.d.ts +16 -0
- package/dist/server/main.js +31 -0
- package/dist/server/sse-route.d.ts +21 -0
- package/dist/server/sse-route.js +282 -0
- package/dist/skills/index.d.ts +67 -0
- package/dist/skills/index.js +31 -0
- package/dist/skills/resolver.d.ts +54 -0
- package/dist/skills/resolver.js +121 -0
- package/dist/teams/index.d.ts +93 -0
- package/dist/teams/index.js +207 -0
- package/dist/telemetry/index.d.ts +157 -0
- package/dist/telemetry/index.js +71 -0
- package/dist/telemetry/instrument.d.ts +108 -0
- package/dist/telemetry/instrument.js +232 -0
- package/dist/telemetry/log-events.d.ts +17 -0
- package/dist/telemetry/log-events.js +58 -0
- package/dist/telemetry/metrics.d.ts +123 -0
- package/dist/telemetry/metrics.js +135 -0
- package/dist/telemetry/noop.d.ts +39 -0
- package/dist/telemetry/noop.js +143 -0
- package/dist/telemetry/redaction.d.ts +64 -0
- package/dist/telemetry/redaction.js +153 -0
- package/dist/telemetry/spans.d.ts +56 -0
- package/dist/telemetry/spans.js +78 -0
- package/dist/telemetry/trace-context.d.ts +55 -0
- package/dist/telemetry/trace-context.js +60 -0
- package/dist/toolkit/compute.d.ts +53 -0
- package/dist/toolkit/compute.js +152 -0
- package/dist/toolkit/data.d.ts +98 -0
- package/dist/toolkit/data.js +235 -0
- package/dist/toolkit/http.d.ts +113 -0
- package/dist/toolkit/http.js +205 -0
- package/dist/toolkit/index.d.ts +21 -0
- package/dist/toolkit/index.js +17 -0
- package/dist/toolkit/web.d.ts +107 -0
- package/dist/toolkit/web.js +147 -0
- package/dist/tools/define.d.ts +25 -0
- package/dist/tools/define.js +45 -0
- package/dist/tools/delegating.d.ts +132 -0
- package/dist/tools/delegating.js +211 -0
- package/dist/tools/index.d.ts +129 -0
- package/dist/tools/index.js +33 -0
- package/dist/tools/library/compute.d.ts +11 -0
- package/dist/tools/library/compute.js +46 -0
- package/dist/tools/library/data.d.ts +16 -0
- package/dist/tools/library/data.js +92 -0
- package/dist/tools/library/http.d.ts +28 -0
- package/dist/tools/library/http.js +71 -0
- package/dist/tools/library/index.d.ts +97 -0
- package/dist/tools/library/index.js +134 -0
- package/dist/tools/library/knowledge.d.ts +39 -0
- package/dist/tools/library/knowledge.js +58 -0
- package/dist/tools/library/web.d.ts +19 -0
- package/dist/tools/library/web.js +65 -0
- package/dist/tools/meta-tools.d.ts +19 -0
- package/dist/tools/meta-tools.js +36 -0
- package/dist/tools/registry.d.ts +146 -0
- package/dist/tools/registry.js +291 -0
- package/dist/usage/index.d.ts +105 -0
- package/dist/usage/index.js +20 -0
- package/dist/usage/quota.d.ts +258 -0
- package/dist/usage/quota.js +510 -0
- package/dist/usage/recorder.d.ts +29 -0
- package/dist/usage/recorder.js +96 -0
- package/dist/usage/rollups.d.ts +121 -0
- package/dist/usage/rollups.js +157 -0
- package/dist/worker/export.d.ts +57 -0
- package/dist/worker/export.js +81 -0
- package/dist/worker/extraction.d.ts +57 -0
- package/dist/worker/extraction.js +84 -0
- package/dist/worker/main.d.ts +103 -0
- package/dist/worker/main.js +159 -0
- package/package.json +187 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { ExecutionContext } from "../core/context.js";
|
|
2
|
+
import type { AuthorizationPolicy } from "../authorization/index.js";
|
|
3
|
+
import { type IdempotencyKey, type IdempotencyStore } from "../idempotency/index.js";
|
|
4
|
+
import type { ApprovalGate } from "../hitl/service.js";
|
|
5
|
+
import { type ToolSpec } from "./define.js";
|
|
6
|
+
import { type SchemaValidator, type ToolMisconfiguration } from "./registry.js";
|
|
7
|
+
import type { ShadowRecorder, Tool } from "./index.js";
|
|
8
|
+
export type DelegatingToolSpec<I = unknown, O = unknown> = Omit<ToolSpec<I, O>, "execute"> & {
|
|
9
|
+
/**
|
|
10
|
+
* The function this capability wraps, named so a reviewer can see it (AC-6).
|
|
11
|
+
*
|
|
12
|
+
* **Required**, not optional. A comment does not survive review at scale, and "which existing
|
|
13
|
+
* function does this delegate to" is the question the whole bridge exists to make answerable — so a
|
|
14
|
+
* capability that does not say what it wraps cannot be defined.
|
|
15
|
+
*/
|
|
16
|
+
readonly delegatesTo: string;
|
|
17
|
+
/**
|
|
18
|
+
* The deterministic function. Receives validated input, the execution context and the call's
|
|
19
|
+
* idempotency key; returns data or throws. Knows nothing about authorisation or approvals.
|
|
20
|
+
*/
|
|
21
|
+
delegate(input: I, context: ExecutionContext, details: DelegateDetails): Promise<O> | O;
|
|
22
|
+
/**
|
|
23
|
+
* A check that runs **before the approval gate** (#119 AC-4).
|
|
24
|
+
*
|
|
25
|
+
* The general property, not a publishing one: *do not ask a person to authorise something that
|
|
26
|
+
* cannot succeed*. Content validation placed inside the delegate runs after the gate, so a human
|
|
27
|
+
* would already have approved something that then fails — which teaches them their approval does not
|
|
28
|
+
* mean much.
|
|
29
|
+
*
|
|
30
|
+
* Throw to refuse. The thrown error is returned as-is, so a preflight that has structured findings
|
|
31
|
+
* can carry them in `details` rather than flattening them into a sentence.
|
|
32
|
+
*
|
|
33
|
+
* It must be **read-only**. It runs on every call including one that is about to be refused for want
|
|
34
|
+
* of an approval, so a preflight with a side effect would be a side effect that happens without
|
|
35
|
+
* approval — the exact thing the gate exists to prevent.
|
|
36
|
+
*/
|
|
37
|
+
preflight?(input: I, context: ExecutionContext): Promise<void> | void;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* What the envelope tells the delegate about the call itself.
|
|
41
|
+
*
|
|
42
|
+
* An object rather than a bare string so that adding a field later is additive — the same reason
|
|
43
|
+
* `ShareFlowServices` is one object rather than four arguments.
|
|
44
|
+
*/
|
|
45
|
+
export type DelegateDetails = {
|
|
46
|
+
/**
|
|
47
|
+
* The key this call was deduplicated under.
|
|
48
|
+
*
|
|
49
|
+
* Passed on so a delegate can hand it to a downstream service whose own queue needs it. **Not** for
|
|
50
|
+
* the delegate to check: the envelope has already looked it up, and a delegate that consulted it
|
|
51
|
+
* would be doing the lookup twice with the second one unguarded.
|
|
52
|
+
*/
|
|
53
|
+
readonly idempotencyKey: IdempotencyKey;
|
|
54
|
+
};
|
|
55
|
+
export type DelegatingToolDeps = {
|
|
56
|
+
readonly authorization: AuthorizationPolicy;
|
|
57
|
+
/**
|
|
58
|
+
* Consulted for gated effects. Absent means no capability with an external-write or destructive
|
|
59
|
+
* effect can run — refusing is the safe default, since the alternative is performing an unapproved
|
|
60
|
+
* side effect because a dependency was not wired.
|
|
61
|
+
*/
|
|
62
|
+
readonly approvals?: ApprovalGate;
|
|
63
|
+
/**
|
|
64
|
+
* Where "this tool can never run" is reported — #162, the same sink and the same shape the registry uses.
|
|
65
|
+
*
|
|
66
|
+
* Deliberately not a separate type: the case that misled in #155 was wiring one layer and not the other, so
|
|
67
|
+
* a host that reports both through one function sees "registry" and "delegating-envelope" side by side
|
|
68
|
+
* instead of guessing which file to open.
|
|
69
|
+
*/
|
|
70
|
+
readonly onMisconfiguration?: (report: ToolMisconfiguration) => void;
|
|
71
|
+
/**
|
|
72
|
+
* Where a first result is stored so a retry returns it. Absent means gated effects are refused for
|
|
73
|
+
* the same reason: an external write with no replay protection is exactly the thing this envelope
|
|
74
|
+
* exists to prevent. See the open question on #113.
|
|
75
|
+
*/
|
|
76
|
+
readonly idempotency?: IdempotencyStore;
|
|
77
|
+
/**
|
|
78
|
+
* Validates `input` against the spec's `inputSchema` before the delegate is reached (#115 AC-5).
|
|
79
|
+
*
|
|
80
|
+
* Defaults to `zodishValidator`, which passes through anything that is not a zod-like schema — and
|
|
81
|
+
* `inputSchema` itself defaults to `{}` — so a tool that declares no schema behaves exactly as it did
|
|
82
|
+
* before this existed.
|
|
83
|
+
*
|
|
84
|
+
* The registry already re-validates at execution, which covers the production path. This covers
|
|
85
|
+
* *every* path: a tool executed directly, from a test, or from a future caller that is not the
|
|
86
|
+
* registry. The envelope's whole purpose is that a guarantee cannot be reached around.
|
|
87
|
+
*/
|
|
88
|
+
readonly validator?: SchemaValidator;
|
|
89
|
+
/**
|
|
90
|
+
* Where a shadow run's suppressed writes go.
|
|
91
|
+
*
|
|
92
|
+
* Required *when the run says it is shadow*: `context.shadow === true` with no recorder is refused
|
|
93
|
+
* rather than performed. Announcing a shadow run and having nowhere to record it is not a licence to
|
|
94
|
+
* publish — the same fail-closed reasoning as the missing approval gate.
|
|
95
|
+
*/
|
|
96
|
+
readonly shadow?: ShadowRecorder;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* The key used when the caller supplied none.
|
|
100
|
+
*
|
|
101
|
+
* **Weaker protection than the caller's key, and stronger collision behaviour — both worth knowing.**
|
|
102
|
+
* `ToolExecutionInput.idempotencyKey` is documented as derived from tenant, run and tool-call identity,
|
|
103
|
+
* which makes a *retry of one call* safe. This fallback is derived from tenant, conversation, tool and
|
|
104
|
+
* normalised arguments, as the SPEC describes, which collides for *any* call with identical arguments
|
|
105
|
+
* **across runs**: "publish this post" today and the same call next week produce the same key, so the
|
|
106
|
+
* second would return the first result and never publish.
|
|
107
|
+
*
|
|
108
|
+
* That is suppression of an intended action rather than deduplication of a retry, so the caller's key
|
|
109
|
+
* is always preferred. This exists only so a tool invoked without one is not left unprotected. See the
|
|
110
|
+
* open question on #113 about whether the run belongs in it.
|
|
111
|
+
*/
|
|
112
|
+
export declare const fallbackIdempotencyKey: (input: {
|
|
113
|
+
readonly context: ExecutionContext;
|
|
114
|
+
readonly toolName: string;
|
|
115
|
+
readonly args: unknown;
|
|
116
|
+
}) => IdempotencyKey;
|
|
117
|
+
/**
|
|
118
|
+
* Build a `Tool` whose execute path is: authorise → validate → derive key → look up → preflight → shadow →
|
|
119
|
+
* approval gate → delegate → store.
|
|
120
|
+
*
|
|
121
|
+
* The lookup sits **before** the approval gate deliberately. A call whose result is already stored has
|
|
122
|
+
* already been approved and executed, so re-gating it would either block a legitimate replay or ask a
|
|
123
|
+
* human to approve one action twice.
|
|
124
|
+
*
|
|
125
|
+
* The descriptor comes from `defineTool` and the error envelope from the same `toPlatformError` a
|
|
126
|
+
* delegating tool's shape is the existing `ToolResult` **by construction** rather than by resemblance
|
|
127
|
+
* (AC-5). The execute path is written out here rather than passed to `defineTool`, because the
|
|
128
|
+
* idempotency key arrives on `ToolExecutionInput` and `defineTool`'s `execute(input, context)` does not
|
|
129
|
+
* carry it — bridging that with a side table keyed by context worked but read like a trick.
|
|
130
|
+
*/
|
|
131
|
+
export declare const defineDelegatingTool: <I = unknown, O = unknown>(deps: DelegatingToolDeps, spec: DelegatingToolSpec<I, O>) => Tool<O>;
|
|
132
|
+
//# sourceMappingURL=delegating.d.ts.map
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The logic-function tool envelope — `docs/extraction/twenty-sdk-comparison.md` (#113).
|
|
3
|
+
*
|
|
4
|
+
* The extraction doc's central decision: *"a tool is a thin, agent-facing envelope over a
|
|
5
|
+
* deterministic function"* that *"adds the permission filter, the approval gate for external writes
|
|
6
|
+
* and the idempotency key, then delegates the actual side effect."* Until now that existed only as
|
|
7
|
+
* prose — there was no `logic-function` reference anywhere in `src`.
|
|
8
|
+
*
|
|
9
|
+
* The point of putting it here rather than in each tool is that **a tool cannot forget**. A capability
|
|
10
|
+
* author writes a `delegate` that does one thing; authorisation, the approval gate and the idempotency
|
|
11
|
+
* key are applied by construction, in one place, in one order.
|
|
12
|
+
*
|
|
13
|
+
* **The delegate is not told whether an approval happened.** It receives validated input, a context and
|
|
14
|
+
* the call's idempotency key, and returns data — which is what makes a wrapped function still a plain
|
|
15
|
+
* function, testable on its own.
|
|
16
|
+
*
|
|
17
|
+
* The key was originally withheld too, on the reasoning that a delegate should know nothing about any
|
|
18
|
+
* of this. Writing the first capability that performs a write (#115) showed that to be wrong: the
|
|
19
|
+
* downstream service needs the key threaded through so a *re-delivered job* is deduplicated, which is
|
|
20
|
+
* a different guarantee from the one the store here provides. The envelope stops a second agent call;
|
|
21
|
+
* the downstream key stops a second delivery of one accepted call. Either alone leaves a way to post
|
|
22
|
+
* twice, and a delegate that cannot pass the key on cannot close that gap. It is still a plain
|
|
23
|
+
* argument — the delegate remains a function of its inputs.
|
|
24
|
+
*/
|
|
25
|
+
import { AgentPlatformError } from "../core/errors.js";
|
|
26
|
+
import { assertToolAuthorized } from "../authorization/index.js";
|
|
27
|
+
import { canonicalizeArgs } from "../idempotency/index.js";
|
|
28
|
+
import { toPlatformError } from "../runtime/retry.js";
|
|
29
|
+
import { defineTool } from "./define.js";
|
|
30
|
+
import { zodishValidator } from "./registry.js";
|
|
31
|
+
/** Effects that require an approval decision before the side effect happens. */
|
|
32
|
+
const GATED_EFFECTS = new Set(["external-write", "destructive"]);
|
|
33
|
+
/**
|
|
34
|
+
* The key used when the caller supplied none.
|
|
35
|
+
*
|
|
36
|
+
* **Weaker protection than the caller's key, and stronger collision behaviour — both worth knowing.**
|
|
37
|
+
* `ToolExecutionInput.idempotencyKey` is documented as derived from tenant, run and tool-call identity,
|
|
38
|
+
* which makes a *retry of one call* safe. This fallback is derived from tenant, conversation, tool and
|
|
39
|
+
* normalised arguments, as the SPEC describes, which collides for *any* call with identical arguments
|
|
40
|
+
* **across runs**: "publish this post" today and the same call next week produce the same key, so the
|
|
41
|
+
* second would return the first result and never publish.
|
|
42
|
+
*
|
|
43
|
+
* That is suppression of an intended action rather than deduplication of a retry, so the caller's key
|
|
44
|
+
* is always preferred. This exists only so a tool invoked without one is not left unprotected. See the
|
|
45
|
+
* open question on #113 about whether the run belongs in it.
|
|
46
|
+
*/
|
|
47
|
+
export const fallbackIdempotencyKey = (input) => `${input.context.tenantId}:${input.context.conversationId ?? "-"}:${input.toolName}:${canonicalizeArgs(input.args)}`;
|
|
48
|
+
const refuse = (code, message) => new AgentPlatformError({ code, message, retryable: false });
|
|
49
|
+
/**
|
|
50
|
+
* Build a `Tool` whose execute path is: authorise → validate → derive key → look up → preflight → shadow →
|
|
51
|
+
* approval gate → delegate → store.
|
|
52
|
+
*
|
|
53
|
+
* The lookup sits **before** the approval gate deliberately. A call whose result is already stored has
|
|
54
|
+
* already been approved and executed, so re-gating it would either block a legitimate replay or ask a
|
|
55
|
+
* human to approve one action twice.
|
|
56
|
+
*
|
|
57
|
+
* The descriptor comes from `defineTool` and the error envelope from the same `toPlatformError` a
|
|
58
|
+
* delegating tool's shape is the existing `ToolResult` **by construction** rather than by resemblance
|
|
59
|
+
* (AC-5). The execute path is written out here rather than passed to `defineTool`, because the
|
|
60
|
+
* idempotency key arrives on `ToolExecutionInput` and `defineTool`'s `execute(input, context)` does not
|
|
61
|
+
* carry it — bridging that with a side table keyed by context worked but read like a trick.
|
|
62
|
+
*/
|
|
63
|
+
export const defineDelegatingTool = (deps, spec) => {
|
|
64
|
+
const effect = spec.effect ?? "read";
|
|
65
|
+
const gated = GATED_EFFECTS.has(effect);
|
|
66
|
+
// Descriptor defaults — approval policy and idempotency requirement — come from `defineTool`, so a
|
|
67
|
+
// delegating tool and a plain one classify an effect identically.
|
|
68
|
+
const defaults = defineTool({
|
|
69
|
+
...spec,
|
|
70
|
+
execute: () => {
|
|
71
|
+
throw new Error("unreachable: the delegating envelope owns execution");
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
const descriptor = { ...defaults.descriptor, delegatesTo: spec.delegatesTo };
|
|
75
|
+
/**
|
|
76
|
+
* Once per envelope, not once per call — #162 AC-2.
|
|
77
|
+
*
|
|
78
|
+
* An envelope wraps exactly one tool, so "once per tool" is one boolean here, where the registry needs a
|
|
79
|
+
* set. Reported on first execution rather than at construction because that is when the misconfiguration
|
|
80
|
+
* first has a consequence, and because a tool that is never called has no wiring bug worth reporting.
|
|
81
|
+
*/
|
|
82
|
+
let reportedMisconfiguration = false;
|
|
83
|
+
const reportMisconfiguration = (toolName, approvalPolicy) => {
|
|
84
|
+
if (deps.onMisconfiguration === undefined || reportedMisconfiguration)
|
|
85
|
+
return;
|
|
86
|
+
reportedMisconfiguration = true;
|
|
87
|
+
deps.onMisconfiguration({
|
|
88
|
+
kind: "approval-check-missing",
|
|
89
|
+
layer: "delegating-envelope",
|
|
90
|
+
toolName,
|
|
91
|
+
approvalPolicy,
|
|
92
|
+
configField: "DelegatingToolDeps.approvals",
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
descriptor,
|
|
97
|
+
async execute({ context, input, idempotencyKey, approval }) {
|
|
98
|
+
try {
|
|
99
|
+
// Re-authorised here even though discovery already filtered the catalog: the governing
|
|
100
|
+
// principle is that tools are filtered before discovery *and* re-authorised during execution,
|
|
101
|
+
// because a role can change between the two and a stale catalog must not be a permission.
|
|
102
|
+
await assertToolAuthorized(deps.authorization, context, {
|
|
103
|
+
name: spec.name,
|
|
104
|
+
category: descriptor.category,
|
|
105
|
+
});
|
|
106
|
+
// Validated *before* the key is derived, not after.
|
|
107
|
+
//
|
|
108
|
+
// Because a schema may normalise — an LLM passes "LinkedIn" where the store keeps "linkedin" —
|
|
109
|
+
// deriving the fallback key from the raw arguments would give one logical call two different
|
|
110
|
+
// keys, and the second would not see the first's result. Normalising first makes the key a
|
|
111
|
+
// property of the call rather than of the model's capitalisation.
|
|
112
|
+
//
|
|
113
|
+
// After authorisation, so a caller with no permission learns nothing about the schema.
|
|
114
|
+
const validated = (deps.validator ?? zodishValidator).validate(descriptor.inputSchema, input);
|
|
115
|
+
if (!validated.ok)
|
|
116
|
+
throw new AgentPlatformError({
|
|
117
|
+
code: "invalid_input",
|
|
118
|
+
message: `Invalid input for ${spec.name}: ${validated.message}`,
|
|
119
|
+
retryable: false,
|
|
120
|
+
});
|
|
121
|
+
// The caller's key is preferred — it is derived from tool-call identity, which is what makes a
|
|
122
|
+
// *retry* safe. The fallback is broader and can suppress an intended repeat; see its docstring.
|
|
123
|
+
const key = idempotencyKey ??
|
|
124
|
+
fallbackIdempotencyKey({ context, toolName: spec.name, args: validated.value });
|
|
125
|
+
if (deps.idempotency) {
|
|
126
|
+
const stored = await deps.idempotency.get({ tenantId: context.tenantId, key });
|
|
127
|
+
// A hit means this call already ran. Returning the stored result *is* the guarantee: the
|
|
128
|
+
// delegate is not called again, so the side effect does not happen twice.
|
|
129
|
+
if (stored)
|
|
130
|
+
return { ok: true, data: stored.result };
|
|
131
|
+
}
|
|
132
|
+
else if (gated) {
|
|
133
|
+
// Refusing rather than proceeding. An external write with no replay protection is precisely
|
|
134
|
+
// what this envelope exists to prevent, and an unwired dependency is not a reason to do it.
|
|
135
|
+
throw refuse("capability_unavailable", `${spec.name} performs a ${effect} and no idempotency store is configured`);
|
|
136
|
+
}
|
|
137
|
+
// Before the gate, and after the idempotency lookup: a call whose result is already stored has
|
|
138
|
+
// already run, so re-validating it could refuse a legitimate replay on content that has since
|
|
139
|
+
// changed underneath it.
|
|
140
|
+
if (spec.preflight)
|
|
141
|
+
await spec.preflight(validated.value, context);
|
|
142
|
+
// Shadow mode, and **before** the approval gate.
|
|
143
|
+
//
|
|
144
|
+
// A shadow run must not ask a human to approve something that will not happen; doing so teaches
|
|
145
|
+
// people that approving is meaningless, which is the one thing an approval gate cannot survive.
|
|
146
|
+
//
|
|
147
|
+
// Only gated effects are suppressed — `external-write` and `destructive`. docs/07 says "shadow
|
|
148
|
+
// execution performs no external *writes*", so an internal write still happens, and that is worth
|
|
149
|
+
// knowing: a shadow run does create real drafts. See the note on #126.
|
|
150
|
+
if (gated && context.shadow === true) {
|
|
151
|
+
if (!deps.shadow)
|
|
152
|
+
throw refuse("capability_unavailable", `${spec.name} is a ${effect} and this run is in shadow mode with no recorder configured`);
|
|
153
|
+
await deps.shadow.record(context, {
|
|
154
|
+
...(context.runId === undefined ? {} : { runId: context.runId }),
|
|
155
|
+
toolName: spec.name,
|
|
156
|
+
delegatesTo: spec.delegatesTo,
|
|
157
|
+
effect,
|
|
158
|
+
input: validated.value,
|
|
159
|
+
idempotencyKey: key,
|
|
160
|
+
wouldRequireApproval: descriptor.approvalPolicy !== "never",
|
|
161
|
+
});
|
|
162
|
+
// Marked truthfully, and this is the least-bad of three bad options. A fake success would teach
|
|
163
|
+
// the agent to report a publish that never happened; a hard failure would change the trajectory
|
|
164
|
+
// parity measurement is trying to observe; this changes it too, but honestly.
|
|
165
|
+
//
|
|
166
|
+
// The limitation is inherent and worth stating rather than hiding: shadow mode measures
|
|
167
|
+
// everything up to the external write and nothing after it. What an agent does *after*
|
|
168
|
+
// publishing cannot be observed without publishing.
|
|
169
|
+
//
|
|
170
|
+
// Not stored under the idempotency key: a suppressed call must not become the cached answer for
|
|
171
|
+
// a later real one.
|
|
172
|
+
return { ok: true, data: { suppressed: true, reason: "shadow-mode", wouldHaveCalled: spec.delegatesTo } };
|
|
173
|
+
}
|
|
174
|
+
if (gated) {
|
|
175
|
+
if (!deps.approvals) {
|
|
176
|
+
// Already distinguishable from a real refusal — `capability_unavailable`, not
|
|
177
|
+
// `approval_required`. #162 adds only the once-per-tool report, so the two layers behave alike.
|
|
178
|
+
reportMisconfiguration(spec.name, descriptor.approvalPolicy);
|
|
179
|
+
throw refuse("capability_unavailable", `${spec.name} performs a ${effect} and no approval gate is configured ` +
|
|
180
|
+
`(DelegatingToolDeps.approvals), so it can never run. This is a wiring error, not a refusal.`);
|
|
181
|
+
}
|
|
182
|
+
// The ticket, when the call carries one, is handed to the gate rather than interpreted here:
|
|
183
|
+
// this envelope decides *whether* approval applies, `hitl/service.ts` decides whether a
|
|
184
|
+
// given approval is real. An envelope that read the ticket itself would be a second place
|
|
185
|
+
// that could get "is this approved" wrong.
|
|
186
|
+
const allowed = await deps.approvals.isAllowed(context, {
|
|
187
|
+
name: spec.name,
|
|
188
|
+
category: descriptor.category,
|
|
189
|
+
approvalPolicy: descriptor.approvalPolicy,
|
|
190
|
+
}, approval);
|
|
191
|
+
// The delegate is never reached. It is not told an approval was needed, refused or granted —
|
|
192
|
+
// this envelope decides *whether* approval applies; `hitl/service.ts` decides *how*.
|
|
193
|
+
if (!allowed) {
|
|
194
|
+
throw refuse("approval_required", `${spec.name} requires approval before it can run`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const data = await spec.delegate(validated.value, context, { idempotencyKey: key });
|
|
198
|
+
// Stored only after the delegate succeeds, so a failed attempt can be retried rather than
|
|
199
|
+
// having its own failure permanently cached as the answer.
|
|
200
|
+
if (deps.idempotency) {
|
|
201
|
+
await deps.idempotency.put({ tenantId: context.tenantId, key, result: data });
|
|
202
|
+
}
|
|
203
|
+
return { ok: true, data };
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
return { ok: false, error: toPlatformError(error) };
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
//# sourceMappingURL=delegating.js.map
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool registry — `docs/03-intelligence-runtime.md`.
|
|
3
|
+
*
|
|
4
|
+
* The runtime builds a permission-filtered compact catalog. Only commonly required
|
|
5
|
+
* tools are preloaded; other schemas load lazily. Execution rechecks authorization and
|
|
6
|
+
* validates input even when the tool was discoverable earlier.
|
|
7
|
+
*/
|
|
8
|
+
import type { ExecutionContext } from "../core/context.js";
|
|
9
|
+
import type { PlatformError } from "../core/errors.js";
|
|
10
|
+
import type { BlobRef } from "../core/ids.js";
|
|
11
|
+
import type { IdempotencyKey } from "../idempotency/index.js";
|
|
12
|
+
/**
|
|
13
|
+
* Effect classification. This drives the approval policy, so an unknown effect is
|
|
14
|
+
* never treated as `read` — see `../mcp` for how imported tools are classified.
|
|
15
|
+
*/
|
|
16
|
+
export declare const TOOL_EFFECTS: readonly ["read", "internal-write", "external-write", "destructive"];
|
|
17
|
+
export type ToolEffect = (typeof TOOL_EFFECTS)[number];
|
|
18
|
+
export type ApprovalPolicy = "never" | "policy" | "always";
|
|
19
|
+
export type ToolDescriptor = {
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly label: string;
|
|
22
|
+
readonly description: string;
|
|
23
|
+
readonly category: string;
|
|
24
|
+
/** JSON Schema. Validated on execution, not merely advertised. */
|
|
25
|
+
readonly inputSchema: unknown;
|
|
26
|
+
readonly outputSchema: unknown;
|
|
27
|
+
readonly effect: ToolEffect;
|
|
28
|
+
readonly approvalPolicy: ApprovalPolicy;
|
|
29
|
+
/** External and destructive tools must supply an idempotency key. */
|
|
30
|
+
readonly requiresIdempotencyKey: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* For a delegating tool (#113): the deterministic function this capability wraps.
|
|
33
|
+
*
|
|
34
|
+
* On the descriptor rather than only at the definition site, so "which existing function does this
|
|
35
|
+
* delegate to" is answerable wherever a tool is visible — a catalog dump, a log line, a review.
|
|
36
|
+
* Optional because a tool need not delegate; required by `defineDelegatingTool` for those that do.
|
|
37
|
+
*/
|
|
38
|
+
readonly delegatesTo?: string;
|
|
39
|
+
};
|
|
40
|
+
/** What enters the model's context during discovery: no schemas, just enough to choose. */
|
|
41
|
+
export type ToolCatalogEntry = Pick<ToolDescriptor, "name" | "label" | "description" | "category" | "effect">;
|
|
42
|
+
/** Shared success/error envelope — every tool, including imported ones. */
|
|
43
|
+
export type ToolResult<T = unknown> = {
|
|
44
|
+
readonly ok: true;
|
|
45
|
+
readonly data: T;
|
|
46
|
+
/** Set when the payload was compacted or spilled rather than returned inline. */
|
|
47
|
+
readonly spilledOutputRef?: BlobRef;
|
|
48
|
+
readonly truncated?: boolean;
|
|
49
|
+
} | {
|
|
50
|
+
readonly ok: false;
|
|
51
|
+
readonly error: PlatformError;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* A single approved execution, presented at the moment of the call.
|
|
55
|
+
*
|
|
56
|
+
* Structural on purpose — the tools layer must not depend on `hitl` (the approval *check* is a
|
|
57
|
+
* structural port here for the same reason). The id is opaque to everything in this layer: whoever
|
|
58
|
+
* implements the check verifies it against the stored interaction, so passing one along is never the
|
|
59
|
+
* same as granting anything.
|
|
60
|
+
*/
|
|
61
|
+
export type OneTimeApprovalRef = {
|
|
62
|
+
readonly interactionId: string;
|
|
63
|
+
};
|
|
64
|
+
export type ToolExecutionInput = {
|
|
65
|
+
readonly context: ExecutionContext;
|
|
66
|
+
readonly input: unknown;
|
|
67
|
+
/** Derived from tenant, run and tool-call identity. Replays return the first result. */
|
|
68
|
+
readonly idempotencyKey?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Set when this call is the execution a human already approved.
|
|
71
|
+
*
|
|
72
|
+
* Threaded down to the tool rather than consumed by the registry alone, because a delegating tool
|
|
73
|
+
* runs its own gate — the registry letting the call through while the envelope refuses it one layer
|
|
74
|
+
* lower is the same stuck loop, just harder to see.
|
|
75
|
+
*/
|
|
76
|
+
readonly approval?: OneTimeApprovalRef;
|
|
77
|
+
};
|
|
78
|
+
export interface Tool<T = unknown> {
|
|
79
|
+
readonly descriptor: ToolDescriptor;
|
|
80
|
+
execute(input: ToolExecutionInput): Promise<ToolResult<T>>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* What a shadow run records instead of doing.
|
|
84
|
+
*
|
|
85
|
+
* A port rather than a store, because what "recording" means differs by deployment: a parity harness wants
|
|
86
|
+
* it in memory, a migration wants it durable and comparable to the old runtime's output.
|
|
87
|
+
*
|
|
88
|
+
* Here rather than in `delegating.ts` because **two layers suppress**: the registry (which covers every
|
|
89
|
+
* tool) and the delegating envelope (which covers the direct-execute path). One definition, for the reason
|
|
90
|
+
* #113's duplicate `toPlatformError` had to be collapsed — two would drift, and a recorder the two layers
|
|
91
|
+
* disagreed about would under-report exactly the writes it exists to catch.
|
|
92
|
+
*/
|
|
93
|
+
export type SuppressedWrite = {
|
|
94
|
+
readonly runId?: string;
|
|
95
|
+
readonly toolName: string;
|
|
96
|
+
/** The function that would have been called. */
|
|
97
|
+
readonly delegatesTo: string;
|
|
98
|
+
readonly effect: ToolEffect;
|
|
99
|
+
/** Validated input — what would have been sent. */
|
|
100
|
+
readonly input: unknown;
|
|
101
|
+
readonly idempotencyKey: IdempotencyKey;
|
|
102
|
+
/**
|
|
103
|
+
* Whether this action would have required a human's approval.
|
|
104
|
+
*
|
|
105
|
+
* Captured because suppression happens *before* the approval gate — a shadow run must not ask someone to
|
|
106
|
+
* approve something that will not happen, since that teaches them approving is meaningless. Recording it
|
|
107
|
+
* keeps the fact the parity report wants without asking the question.
|
|
108
|
+
*/
|
|
109
|
+
readonly wouldRequireApproval: boolean;
|
|
110
|
+
};
|
|
111
|
+
export interface ShadowRecorder {
|
|
112
|
+
record(context: ExecutionContext, write: SuppressedWrite): Promise<void> | void;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Applications register providers rather than individual tools, so a provider can
|
|
116
|
+
* resolve its tool list against tenant configuration.
|
|
117
|
+
*/
|
|
118
|
+
export interface ToolProvider {
|
|
119
|
+
readonly id: string;
|
|
120
|
+
listTools(context: ExecutionContext): Promise<readonly Tool[]>;
|
|
121
|
+
}
|
|
122
|
+
/** Built-in meta-tools. Always present, never provider-supplied. */
|
|
123
|
+
export declare const META_TOOLS: readonly ["learn_tools", "execute_tool", "load_skill", "ask_questions", "request_approval", "read_tool_output"];
|
|
124
|
+
export type MetaToolName = (typeof META_TOOLS)[number];
|
|
125
|
+
export * from "./meta-tools.js";
|
|
126
|
+
export * from "./registry.js";
|
|
127
|
+
export * from "./delegating.js";
|
|
128
|
+
export * from "./define.js";
|
|
129
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool registry — `docs/03-intelligence-runtime.md`.
|
|
3
|
+
*
|
|
4
|
+
* The runtime builds a permission-filtered compact catalog. Only commonly required
|
|
5
|
+
* tools are preloaded; other schemas load lazily. Execution rechecks authorization and
|
|
6
|
+
* validates input even when the tool was discoverable earlier.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Effect classification. This drives the approval policy, so an unknown effect is
|
|
10
|
+
* never treated as `read` — see `../mcp` for how imported tools are classified.
|
|
11
|
+
*/
|
|
12
|
+
export const TOOL_EFFECTS = [
|
|
13
|
+
"read",
|
|
14
|
+
"internal-write",
|
|
15
|
+
"external-write",
|
|
16
|
+
"destructive",
|
|
17
|
+
];
|
|
18
|
+
// The authorization port lives in `../authorization` (docs/11) — a single canonical definition
|
|
19
|
+
// used for both discovery filtering and execution permission.
|
|
20
|
+
/** Built-in meta-tools. Always present, never provider-supplied. */
|
|
21
|
+
export const META_TOOLS = [
|
|
22
|
+
"learn_tools",
|
|
23
|
+
"execute_tool",
|
|
24
|
+
"load_skill",
|
|
25
|
+
"ask_questions",
|
|
26
|
+
"request_approval",
|
|
27
|
+
"read_tool_output",
|
|
28
|
+
];
|
|
29
|
+
export * from "./meta-tools.js";
|
|
30
|
+
export * from "./registry.js";
|
|
31
|
+
export * from "./delegating.js";
|
|
32
|
+
export * from "./define.js";
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time and arithmetic — REQ-039 (#188).
|
|
3
|
+
*
|
|
4
|
+
* The two things worth shipping because a model is reliably bad at them: it has no clock, and it does arithmetic
|
|
5
|
+
* by pattern rather than by calculation. Both delegate to pure functions in `toolkit/compute.ts`.
|
|
6
|
+
*/
|
|
7
|
+
import type { DelegatingToolDeps } from "../delegating.js";
|
|
8
|
+
import type { Tool } from "../index.js";
|
|
9
|
+
export declare const createNowTool: (deps: DelegatingToolDeps, now?: () => Date) => Tool;
|
|
10
|
+
export declare const createCalculateTool: (deps: DelegatingToolDeps) => Tool;
|
|
11
|
+
//# sourceMappingURL=compute.d.ts.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time and arithmetic — REQ-039 (#188).
|
|
3
|
+
*
|
|
4
|
+
* The two things worth shipping because a model is reliably bad at them: it has no clock, and it does arithmetic
|
|
5
|
+
* by pattern rather than by calculation. Both delegate to pure functions in `toolkit/compute.ts`.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { defineDelegatingTool } from "../delegating.js";
|
|
9
|
+
import { calculate, currentTime } from "../../toolkit/compute.js";
|
|
10
|
+
const timeSchema = z
|
|
11
|
+
.object({
|
|
12
|
+
timeZone: z.string().min(1).max(64).optional().describe("An IANA zone like 'Europe/Berlin'. Defaults to the caller's."),
|
|
13
|
+
})
|
|
14
|
+
.strict();
|
|
15
|
+
export const createNowTool = (deps, now) => defineDelegatingTool(deps, {
|
|
16
|
+
name: "now",
|
|
17
|
+
label: "Current date and time",
|
|
18
|
+
description: "The current date and time. Call this before any answer that depends on today — you do not have a clock, " +
|
|
19
|
+
"and the date you would otherwise assume is the one you were trained on.",
|
|
20
|
+
category: "general",
|
|
21
|
+
effect: "read",
|
|
22
|
+
inputSchema: timeSchema,
|
|
23
|
+
delegatesTo: "toolkit/compute.currentTime",
|
|
24
|
+
delegate: (input, context) =>
|
|
25
|
+
// The context's timezone when the caller named none: "today" is a different day depending on where the
|
|
26
|
+
// person asking is, and the execution context already knows which.
|
|
27
|
+
currentTime({ timeZone: input.timeZone ?? context.timezone, now }),
|
|
28
|
+
});
|
|
29
|
+
const calculateSchema = z
|
|
30
|
+
.object({
|
|
31
|
+
expression: z.string().min(1).max(500).describe("Arithmetic: + - * / % ^, parentheses, and functions like sqrt, round, min."),
|
|
32
|
+
})
|
|
33
|
+
.strict();
|
|
34
|
+
export const createCalculateTool = (deps) => defineDelegatingTool(deps, {
|
|
35
|
+
name: "calculate",
|
|
36
|
+
label: "Calculate",
|
|
37
|
+
description: "Evaluate an arithmetic expression exactly. Use this for any arithmetic that matters rather than doing it " +
|
|
38
|
+
"yourself. Supports + - * / % ^, parentheses, and abs, ceil, floor, round, sqrt, ln, log10, min, max, pow, " +
|
|
39
|
+
"and the trigonometric functions. Results are double-precision floats.",
|
|
40
|
+
category: "general",
|
|
41
|
+
effect: "read",
|
|
42
|
+
inputSchema: calculateSchema,
|
|
43
|
+
delegatesTo: "toolkit/compute.calculate",
|
|
44
|
+
delegate: (input) => calculate(input.expression),
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=compute.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured data — REQ-039 (#188).
|
|
3
|
+
*
|
|
4
|
+
* Envelopes over `toolkit/data.ts`. `parse_csv` and `query_json` are pure and take their input as text, which is
|
|
5
|
+
* the deliberate shape: a tool that took a *path* or a *URL* would be a file read or a fetch wearing a parser's
|
|
6
|
+
* name, and the authorisation for those belongs to `read_attachment` and `fetch_url`. So the model reads with one
|
|
7
|
+
* tool and parses with another, and each one is checked by the thing that should check it.
|
|
8
|
+
*/
|
|
9
|
+
import type { DelegatingToolDeps } from "../delegating.js";
|
|
10
|
+
import type { Tool } from "../index.js";
|
|
11
|
+
import type { SchemaResult, SqlResult } from "../../toolkit/index.js";
|
|
12
|
+
export declare const createParseCsvTool: (deps: DelegatingToolDeps) => Tool;
|
|
13
|
+
export declare const createQueryJsonTool: (deps: DelegatingToolDeps) => Tool;
|
|
14
|
+
export declare const createSqlQueryTool: (deps: DelegatingToolDeps, run: (sql: string) => Promise<SqlResult>) => Tool;
|
|
15
|
+
export declare const createSqlSchemaTool: (deps: DelegatingToolDeps, describe: () => Promise<SchemaResult>) => Tool;
|
|
16
|
+
//# sourceMappingURL=data.d.ts.map
|