@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,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE transport adapter — `docs/06` (embedded-profile streaming). A thin mapping from the
|
|
3
|
+
* transport-neutral `RunEvent` stream to Server-Sent Events frames. It takes no HTTP-framework
|
|
4
|
+
* dependency: `sseFrames` yields ready-to-write text frames, and `openRunEventSse` composes the
|
|
5
|
+
* reconnect stream (catch-up + live) with SSE encoding. The `Last-Event-ID` header a browser
|
|
6
|
+
* resends on reconnect maps directly to the run event `sequence`, so resuming loses no events.
|
|
7
|
+
*/
|
|
8
|
+
import { openRunEventStream } from "../runtime/index.js";
|
|
9
|
+
/**
|
|
10
|
+
* The GraphQL field the frames are shaped for.
|
|
11
|
+
*
|
|
12
|
+
* Hard-coded to match the SDL's `runEvents` subscription, because that is the selection a client made.
|
|
13
|
+
* A client that *aliased* the field would look for its alias and not find it — see the open question
|
|
14
|
+
* on #111; the adapter has no way to know the alias.
|
|
15
|
+
*/
|
|
16
|
+
export const SSE_RESULT_FIELD = "runEvents";
|
|
17
|
+
/**
|
|
18
|
+
* Encode one event as a graphql-sse `next` frame.
|
|
19
|
+
*
|
|
20
|
+
* `docs/extraction/twenty-sdk-comparison.md` records the decision: *"Match the `graphql-sse` framing
|
|
21
|
+
* rather than inventing a bespoke SSE protocol"* — twenty-sdk already streams GraphQL over graphql-sse,
|
|
22
|
+
* so a client can consume this unmodified. This previously emitted `event: <RunEvent.type>` with a raw
|
|
23
|
+
* `RunEvent` as `data`, which no graphql-sse client understands.
|
|
24
|
+
*
|
|
25
|
+
* The `id:` line keeps carrying `RunEvent.sequence`, which is what makes `Last-Event-ID` resume work.
|
|
26
|
+
*
|
|
27
|
+
* **A failed run is a `next` frame, not an error frame**, and that is deliberate. `run.failed` is a
|
|
28
|
+
* durable event with a sequence, sitting in the log like any other. Delivering it as a protocol-level
|
|
29
|
+
* error would leave it with no `id:` — so `Last-Event-ID` could not resume past it, and a reconnecting
|
|
30
|
+
* client would never learn the run ended. An `ExecutionResult` may carry both `data` and `errors`, so
|
|
31
|
+
* the event travels in `data` and the platform error in `errors`: clients surface it through their
|
|
32
|
+
* normal error path (which is what AC-3 is for) and resume keeps working.
|
|
33
|
+
*/
|
|
34
|
+
export const toSseFrame = (event) => {
|
|
35
|
+
const result = {
|
|
36
|
+
data: { [SSE_RESULT_FIELD]: event },
|
|
37
|
+
};
|
|
38
|
+
if (event.type === "run.failed") {
|
|
39
|
+
const { error } = event;
|
|
40
|
+
result.errors = [
|
|
41
|
+
{
|
|
42
|
+
message: error.message,
|
|
43
|
+
extensions: { code: error.code, retryable: error.retryable },
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
return `id: ${event.sequence}\nevent: next\ndata: ${JSON.stringify(result)}\n\n`;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* The terminating frame.
|
|
51
|
+
*
|
|
52
|
+
* graphql-sse's distinct-connections mode uses `event: complete` to say the response is finished. A
|
|
53
|
+
* stream that simply stops is indistinguishable from a truncated one, and a client cannot tell whether
|
|
54
|
+
* to reconnect.
|
|
55
|
+
*/
|
|
56
|
+
export const SSE_COMPLETE_FRAME = `event: complete\ndata: \n\n`;
|
|
57
|
+
/**
|
|
58
|
+
* A stream-level failure, in the protocol's error shape.
|
|
59
|
+
*
|
|
60
|
+
* Distinct from a failed *run*: there is no sequence to preserve and nothing to resume to, so this is
|
|
61
|
+
* genuinely a protocol error rather than an event.
|
|
62
|
+
*/
|
|
63
|
+
export const sseErrorFrame = (message) => `event: next\ndata: ${JSON.stringify({ errors: [{ message }] })}\n\n`;
|
|
64
|
+
/** Parse a browser `Last-Event-ID` header into a resume cursor. Missing/invalid ⇒ 0 (from start). */
|
|
65
|
+
export const cursorFromLastEventId = (lastEventId) => {
|
|
66
|
+
const n = Number(lastEventId);
|
|
67
|
+
return Number.isInteger(n) && n >= 0 ? n : 0;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Map a `RunEvent` async stream to graphql-sse text frames, terminated by `complete`.
|
|
71
|
+
*
|
|
72
|
+
* The `complete` frame is emitted in a `finally`, so it is sent whether the stream ended on a terminal
|
|
73
|
+
* event or because the consumer stopped — a client should be told the response is over either way.
|
|
74
|
+
*/
|
|
75
|
+
export async function* sseFrames(events) {
|
|
76
|
+
try {
|
|
77
|
+
for await (const event of events)
|
|
78
|
+
yield toSseFrame(event);
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
yield SSE_COMPLETE_FRAME;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Open a resumable SSE stream for a run: catch up from the durable log after `after`, then follow
|
|
86
|
+
* live, encoded as SSE frames. Ends on the run's terminal event.
|
|
87
|
+
*/
|
|
88
|
+
export const openRunEventSse = (input) => {
|
|
89
|
+
const channel = (input.channelFor ?? ((id) => `conversation:${id}`))(input.conversationId);
|
|
90
|
+
return sseFrames(openRunEventStream({
|
|
91
|
+
tenantId: input.tenantId,
|
|
92
|
+
runId: input.runId,
|
|
93
|
+
channel,
|
|
94
|
+
after: input.after,
|
|
95
|
+
log: input.log,
|
|
96
|
+
live: input.live,
|
|
97
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
98
|
+
}));
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=sse.js.map
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The approval loop's two missing halves — `docs/04-durable-runtime-and-hitl.md` → Approvals.
|
|
3
|
+
*
|
|
4
|
+
* `service.ts` had everything except a path from one end to the other. The gate refused a gated tool,
|
|
5
|
+
* `request` could persist a pending approval with the exact normalized call, `decide` recorded the
|
|
6
|
+
* decision and re-enqueued the run — and nothing joined them. Nothing raised an approval when the gate
|
|
7
|
+
* refused, and nothing read `normalizedInput` back to execute it. So the safe direction held (no
|
|
8
|
+
* external write without a standing grant) while the *default* decision, `allow-once`, could not
|
|
9
|
+
* proceed at all: the model re-requested, the gate refused again, the run looped.
|
|
10
|
+
*
|
|
11
|
+
* This module is that path, and it is deliberately one module rather than a rule spread across the
|
|
12
|
+
* engine and the registry:
|
|
13
|
+
*
|
|
14
|
+
* - **`runTool`** is what a run calls instead of the registry directly. A refusal for want of approval
|
|
15
|
+
* becomes a durable ask rather than an error the model has to interpret.
|
|
16
|
+
* - **`resume`** is what a re-enqueued run calls before it does anything else. It claims the single
|
|
17
|
+
* execution the decision authorizes and runs the **stored** tool and input.
|
|
18
|
+
*
|
|
19
|
+
* **Why the dependency points this way.** `hitl` → `tools`, never the reverse: the tools layer keeps
|
|
20
|
+
* its approval check structural (`ApprovalCheck`) precisely so that the knowledge of what an approval
|
|
21
|
+
* *is* lives here. A registry that understood interactions would be a second place where "is this
|
|
22
|
+
* approved" could be decided, and two such places is one too many.
|
|
23
|
+
*
|
|
24
|
+
* **What is not here.** No grant is issued for `allow-once`, ever. A grant is standing by definition,
|
|
25
|
+
* so turning a one-time decision into one would broaden the authority a human gave — the opposite of
|
|
26
|
+
* what they chose. The single execution is claimed off the interaction instead
|
|
27
|
+
* (`InteractionStore.claimApproval`), which is both narrower and durable across a restart.
|
|
28
|
+
*/
|
|
29
|
+
import type { ExecutionContext } from "../core/context.js";
|
|
30
|
+
import type { RunId } from "../core/ids.js";
|
|
31
|
+
import type { InteractionStore } from "../persistence/index.js";
|
|
32
|
+
import { type SchemaValidator } from "../tools/registry.js";
|
|
33
|
+
import type { OneTimeApprovalRef, ToolDescriptor, ToolResult } from "../tools/index.js";
|
|
34
|
+
import { type ApprovalRequest } from "./service.js";
|
|
35
|
+
import type { PendingApproval } from "./index.js";
|
|
36
|
+
/**
|
|
37
|
+
* What this module needs from the tool layer — the registry satisfies it.
|
|
38
|
+
*
|
|
39
|
+
* Structural rather than `ToolRegistry` so the coupling is exactly two methods wide, and so a host
|
|
40
|
+
* that runs tools some other way can still use the loop.
|
|
41
|
+
*/
|
|
42
|
+
export interface ApprovalToolRunner {
|
|
43
|
+
execute(context: ExecutionContext, input: {
|
|
44
|
+
readonly name: string;
|
|
45
|
+
readonly input: unknown;
|
|
46
|
+
readonly idempotencyKey?: string;
|
|
47
|
+
readonly approval?: OneTimeApprovalRef;
|
|
48
|
+
}): Promise<ToolResult>;
|
|
49
|
+
/** Resolves descriptors for names the caller is authorized to use; unauthorized names are absent. */
|
|
50
|
+
learn(context: ExecutionContext, names: readonly string[]): Promise<readonly ToolDescriptor[]>;
|
|
51
|
+
}
|
|
52
|
+
/** Just the part of the approval service this needs, so a host can substitute its own. */
|
|
53
|
+
export interface ApprovalRequester {
|
|
54
|
+
request(context: ExecutionContext, runId: RunId, request: ApprovalRequest): Promise<PendingApproval>;
|
|
55
|
+
}
|
|
56
|
+
export type GatedCallOutcome =
|
|
57
|
+
/** The call ran (or failed on its own terms) — the ordinary path, approval or no approval. */
|
|
58
|
+
{
|
|
59
|
+
readonly outcome: "result";
|
|
60
|
+
readonly result: ToolResult;
|
|
61
|
+
}
|
|
62
|
+
/** The call needs a human. The run should pause; the approval is durable until decided. */
|
|
63
|
+
| {
|
|
64
|
+
readonly outcome: "approval-requested";
|
|
65
|
+
readonly approval: PendingApproval;
|
|
66
|
+
};
|
|
67
|
+
export type ApprovalResumeOutcome =
|
|
68
|
+
/** Nothing to resume: no decision yet, or the decision was already acted on. */
|
|
69
|
+
{
|
|
70
|
+
readonly outcome: "none";
|
|
71
|
+
} | {
|
|
72
|
+
readonly outcome: "executed";
|
|
73
|
+
readonly approval: PendingApproval;
|
|
74
|
+
readonly result: ToolResult;
|
|
75
|
+
} | {
|
|
76
|
+
readonly outcome: "denied";
|
|
77
|
+
readonly approval: PendingApproval;
|
|
78
|
+
}
|
|
79
|
+
/** Decided too late to act on. Claimed all the same, so the run does not loop on it. */
|
|
80
|
+
| {
|
|
81
|
+
readonly outcome: "expired";
|
|
82
|
+
readonly approval: PendingApproval;
|
|
83
|
+
};
|
|
84
|
+
export type RunApprovalDeps = {
|
|
85
|
+
readonly interactions: InteractionStore;
|
|
86
|
+
readonly approvals: ApprovalRequester;
|
|
87
|
+
readonly tools: ApprovalToolRunner;
|
|
88
|
+
readonly clock?: () => string;
|
|
89
|
+
/** Normalizes a call's arguments before they are stored. Defaults to the registry's validator. */
|
|
90
|
+
readonly validator?: SchemaValidator;
|
|
91
|
+
/** How long a raised approval stays actionable. Default 24h. */
|
|
92
|
+
readonly ttlMs?: number;
|
|
93
|
+
/** The human-facing one-liner on the approval card. Override for a domain-specific rendering. */
|
|
94
|
+
readonly summarize?: (input: {
|
|
95
|
+
readonly descriptor: ToolDescriptor;
|
|
96
|
+
readonly input: unknown;
|
|
97
|
+
}) => string;
|
|
98
|
+
};
|
|
99
|
+
export declare const createRunApprovals: (deps: RunApprovalDeps) => {
|
|
100
|
+
/**
|
|
101
|
+
* Run a tool on behalf of the model, raising a durable approval if the gate refuses it.
|
|
102
|
+
*
|
|
103
|
+
* The order matters. Arguments are resolved and normalized *before* the call, so that the key is a
|
|
104
|
+
* property of the call rather than of the model's capitalization, and so that an approval — if one
|
|
105
|
+
* is needed — stores what will actually run. Invalid input is refused here rather than turned into
|
|
106
|
+
* an approval: asking a person to authorize a call that cannot succeed teaches them their approval
|
|
107
|
+
* is theatre.
|
|
108
|
+
*/
|
|
109
|
+
runTool(context: ExecutionContext, runId: RunId, call: {
|
|
110
|
+
readonly name: string;
|
|
111
|
+
readonly input: unknown;
|
|
112
|
+
}): Promise<GatedCallOutcome>;
|
|
113
|
+
/**
|
|
114
|
+
* Act on a decision, once. Called by a resumed run before it gives the model another turn.
|
|
115
|
+
*
|
|
116
|
+
* The claim comes first — before the decision is even read — because it is the only step that can
|
|
117
|
+
* fail exclusively. A denial and an expiry are claimed too: an unclaimed one would be found again
|
|
118
|
+
* on the next resumption, and the run would spin on a decision it has already honoured.
|
|
119
|
+
*
|
|
120
|
+
* The tool and the input come off the stored approval and nowhere else. That is the whole
|
|
121
|
+
* guarantee: a model-regenerated call after approval means the human approved content that is not
|
|
122
|
+
* what runs.
|
|
123
|
+
*/
|
|
124
|
+
resume(context: ExecutionContext, runId: RunId): Promise<ApprovalResumeOutcome>;
|
|
125
|
+
};
|
|
126
|
+
export type RunApprovals = ReturnType<typeof createRunApprovals>;
|
|
127
|
+
//# sourceMappingURL=approved-execution.d.ts.map
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The approval loop's two missing halves — `docs/04-durable-runtime-and-hitl.md` → Approvals.
|
|
3
|
+
*
|
|
4
|
+
* `service.ts` had everything except a path from one end to the other. The gate refused a gated tool,
|
|
5
|
+
* `request` could persist a pending approval with the exact normalized call, `decide` recorded the
|
|
6
|
+
* decision and re-enqueued the run — and nothing joined them. Nothing raised an approval when the gate
|
|
7
|
+
* refused, and nothing read `normalizedInput` back to execute it. So the safe direction held (no
|
|
8
|
+
* external write without a standing grant) while the *default* decision, `allow-once`, could not
|
|
9
|
+
* proceed at all: the model re-requested, the gate refused again, the run looped.
|
|
10
|
+
*
|
|
11
|
+
* This module is that path, and it is deliberately one module rather than a rule spread across the
|
|
12
|
+
* engine and the registry:
|
|
13
|
+
*
|
|
14
|
+
* - **`runTool`** is what a run calls instead of the registry directly. A refusal for want of approval
|
|
15
|
+
* becomes a durable ask rather than an error the model has to interpret.
|
|
16
|
+
* - **`resume`** is what a re-enqueued run calls before it does anything else. It claims the single
|
|
17
|
+
* execution the decision authorizes and runs the **stored** tool and input.
|
|
18
|
+
*
|
|
19
|
+
* **Why the dependency points this way.** `hitl` → `tools`, never the reverse: the tools layer keeps
|
|
20
|
+
* its approval check structural (`ApprovalCheck`) precisely so that the knowledge of what an approval
|
|
21
|
+
* *is* lives here. A registry that understood interactions would be a second place where "is this
|
|
22
|
+
* approved" could be decided, and two such places is one too many.
|
|
23
|
+
*
|
|
24
|
+
* **What is not here.** No grant is issued for `allow-once`, ever. A grant is standing by definition,
|
|
25
|
+
* so turning a one-time decision into one would broaden the authority a human gave — the opposite of
|
|
26
|
+
* what they chose. The single execution is claimed off the interaction instead
|
|
27
|
+
* (`InteractionStore.claimApproval`), which is both narrower and durable across a restart.
|
|
28
|
+
*/
|
|
29
|
+
import { deriveCallIdempotencyKey } from "../idempotency/index.js";
|
|
30
|
+
import { zodishValidator } from "../tools/registry.js";
|
|
31
|
+
import { isAllowDecision } from "./service.js";
|
|
32
|
+
/** A day. Long enough for a human to come back to it, short enough that a stale ask expires. */
|
|
33
|
+
const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
34
|
+
const APPROVAL_REQUIRED = "approval_required";
|
|
35
|
+
const refusedForApproval = (result) => !result.ok && result.error.code === APPROVAL_REQUIRED;
|
|
36
|
+
export const createRunApprovals = (deps) => {
|
|
37
|
+
const clock = deps.clock ?? (() => new Date().toISOString());
|
|
38
|
+
const validator = deps.validator ?? zodishValidator;
|
|
39
|
+
const ttlMs = deps.ttlMs ?? DEFAULT_TTL_MS;
|
|
40
|
+
const summarize = deps.summarize ?? (({ descriptor }) => `${descriptor.label}: ${descriptor.description}`);
|
|
41
|
+
const expiresAt = () => {
|
|
42
|
+
const base = Date.parse(clock());
|
|
43
|
+
return new Date((Number.isNaN(base) ? Date.now() : base) + ttlMs).toISOString();
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Unparseable timestamps mean "not expired" rather than "expired".
|
|
47
|
+
*
|
|
48
|
+
* Deliberate, and the safer of the two: a false *expired* silently drops an approval a human gave,
|
|
49
|
+
* and the run reports success having done nothing. A false *not expired* still has to get past the
|
|
50
|
+
* claim and the gate, both of which check the decision itself.
|
|
51
|
+
*/
|
|
52
|
+
const isExpired = (approval) => {
|
|
53
|
+
const at = Date.parse(approval.expiresAt);
|
|
54
|
+
const now = Date.parse(clock());
|
|
55
|
+
return !Number.isNaN(at) && !Number.isNaN(now) && at <= now;
|
|
56
|
+
};
|
|
57
|
+
/** The run's context, with the run pinned — the gate checks a ticket against the approval's run. */
|
|
58
|
+
const inRun = (context, runId) => context.runId === runId ? context : { ...context, runId };
|
|
59
|
+
return {
|
|
60
|
+
/**
|
|
61
|
+
* Run a tool on behalf of the model, raising a durable approval if the gate refuses it.
|
|
62
|
+
*
|
|
63
|
+
* The order matters. Arguments are resolved and normalized *before* the call, so that the key is a
|
|
64
|
+
* property of the call rather than of the model's capitalization, and so that an approval — if one
|
|
65
|
+
* is needed — stores what will actually run. Invalid input is refused here rather than turned into
|
|
66
|
+
* an approval: asking a person to authorize a call that cannot succeed teaches them their approval
|
|
67
|
+
* is theatre.
|
|
68
|
+
*/
|
|
69
|
+
async runTool(context, runId, call) {
|
|
70
|
+
const ctx = inRun(context, runId);
|
|
71
|
+
const [descriptor] = await deps.tools.learn(ctx, [call.name]);
|
|
72
|
+
// Unknown or unauthorized: hand it to the runner, whose refusal is the canonical one. Producing
|
|
73
|
+
// our own here would mean two different answers to "may I use this tool".
|
|
74
|
+
if (!descriptor)
|
|
75
|
+
return { outcome: "result", result: await deps.tools.execute(ctx, call) };
|
|
76
|
+
const validated = validator.validate(descriptor.inputSchema, call.input);
|
|
77
|
+
if (!validated.ok) {
|
|
78
|
+
return {
|
|
79
|
+
outcome: "result",
|
|
80
|
+
result: {
|
|
81
|
+
ok: false,
|
|
82
|
+
error: {
|
|
83
|
+
code: "invalid_input",
|
|
84
|
+
message: `Invalid input for ${call.name}: ${validated.message}`,
|
|
85
|
+
retryable: false,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const idempotencyKey = deriveCallIdempotencyKey({
|
|
91
|
+
tenantId: ctx.tenantId,
|
|
92
|
+
runId,
|
|
93
|
+
toolName: call.name,
|
|
94
|
+
args: validated.value,
|
|
95
|
+
});
|
|
96
|
+
const result = await deps.tools.execute(ctx, { name: call.name, input: validated.value, idempotencyKey });
|
|
97
|
+
if (!refusedForApproval(result))
|
|
98
|
+
return { outcome: "result", result };
|
|
99
|
+
/**
|
|
100
|
+
* A shadow run asks for nothing.
|
|
101
|
+
*
|
|
102
|
+
* The envelope suppresses a gated write *before* its own gate, on the reasoning that a shadow run
|
|
103
|
+
* must not ask a human to approve something that will not happen — that teaches people approving
|
|
104
|
+
* is meaningless, which is the one thing an approval gate cannot survive. The registry's gate
|
|
105
|
+
* fires earlier than the envelope's suppression, so a suppressed call can still surface here as a
|
|
106
|
+
* refusal, and raising an approval on it would ask exactly that question.
|
|
107
|
+
*
|
|
108
|
+
* Refusing rather than asking. Nothing executed — the gate already stopped it — so the run is no
|
|
109
|
+
* less safe; it simply does not park a real human decision on a hypothetical action.
|
|
110
|
+
*
|
|
111
|
+
* **The gap this guarded is now closed**, and this is belt and braces rather than the mechanism.
|
|
112
|
+
* Suppression moved into `registry.ts`, *before* its gate — for a reason larger than the missing
|
|
113
|
+
* parity record: the delegating envelope covers delegating tools only, so a gated tool that is not
|
|
114
|
+
* one (every MCP-imported external write) reached its own execute in a shadow run. With the registry
|
|
115
|
+
* suppressing, a gated call in a shadow run no longer refuses here, so this branch is unreachable
|
|
116
|
+
* through `deps.tools`. It stays as a fail-safe if suppression is ever moved again, and is labelled
|
|
117
|
+
* as one rather than left looking load-bearing.
|
|
118
|
+
*/
|
|
119
|
+
if (ctx.shadow === true)
|
|
120
|
+
return { outcome: "result", result };
|
|
121
|
+
// The model asking again for a call already awaiting a decision must not stack a second
|
|
122
|
+
// interaction — the human would see the same request twice and the unique index on
|
|
123
|
+
// (tenant, idempotency_key) would refuse the insert anyway.
|
|
124
|
+
const pending = await deps.interactions.findPendingApproval({ tenantId: ctx.tenantId, runId });
|
|
125
|
+
if (pending && pending.toolName === call.name && pending.idempotencyKey === idempotencyKey) {
|
|
126
|
+
return { outcome: "approval-requested", approval: pending };
|
|
127
|
+
}
|
|
128
|
+
const approval = await deps.approvals.request(ctx, runId, {
|
|
129
|
+
toolName: call.name,
|
|
130
|
+
normalizedInput: validated.value,
|
|
131
|
+
riskCategory: descriptor.category,
|
|
132
|
+
summary: summarize({ descriptor, input: validated.value }),
|
|
133
|
+
expiresAt: expiresAt(),
|
|
134
|
+
idempotencyKey,
|
|
135
|
+
});
|
|
136
|
+
return { outcome: "approval-requested", approval };
|
|
137
|
+
},
|
|
138
|
+
/**
|
|
139
|
+
* Act on a decision, once. Called by a resumed run before it gives the model another turn.
|
|
140
|
+
*
|
|
141
|
+
* The claim comes first — before the decision is even read — because it is the only step that can
|
|
142
|
+
* fail exclusively. A denial and an expiry are claimed too: an unclaimed one would be found again
|
|
143
|
+
* on the next resumption, and the run would spin on a decision it has already honoured.
|
|
144
|
+
*
|
|
145
|
+
* The tool and the input come off the stored approval and nowhere else. That is the whole
|
|
146
|
+
* guarantee: a model-regenerated call after approval means the human approved content that is not
|
|
147
|
+
* what runs.
|
|
148
|
+
*/
|
|
149
|
+
async resume(context, runId) {
|
|
150
|
+
const ctx = inRun(context, runId);
|
|
151
|
+
const decided = await deps.interactions.findDecidedApproval({ tenantId: ctx.tenantId, runId });
|
|
152
|
+
if (!decided)
|
|
153
|
+
return { outcome: "none" };
|
|
154
|
+
const { approval, claimed } = await deps.interactions.claimApproval({
|
|
155
|
+
tenantId: ctx.tenantId,
|
|
156
|
+
interactionId: decided.id,
|
|
157
|
+
at: clock(),
|
|
158
|
+
});
|
|
159
|
+
// Lost the race, or already run. Either way this worker owes no execution.
|
|
160
|
+
if (!claimed)
|
|
161
|
+
return { outcome: "none" };
|
|
162
|
+
if (!isAllowDecision(approval.decision))
|
|
163
|
+
return { outcome: "denied", approval };
|
|
164
|
+
if (isExpired(approval))
|
|
165
|
+
return { outcome: "expired", approval };
|
|
166
|
+
const result = await deps.tools.execute(ctx, {
|
|
167
|
+
name: approval.toolName,
|
|
168
|
+
input: approval.normalizedInput,
|
|
169
|
+
idempotencyKey: approval.idempotencyKey,
|
|
170
|
+
// The claim is what the gate verifies: it proves this execution is the one the decision bought.
|
|
171
|
+
approval: { interactionId: approval.id },
|
|
172
|
+
});
|
|
173
|
+
return { outcome: "executed", approval, result };
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
//# sourceMappingURL=approved-execution.js.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable questions and approvals — `docs/04-durable-runtime-and-hitl.md`.
|
|
3
|
+
*/
|
|
4
|
+
import type { ApprovalGrantId, InteractionId, RunId, TenantId } from "../core/ids.js";
|
|
5
|
+
import type { QuestionAnswer } from "../core/content-parts.js";
|
|
6
|
+
import type { QuestionSpec } from "./service.js";
|
|
7
|
+
export type PendingQuestion = {
|
|
8
|
+
readonly id: InteractionId;
|
|
9
|
+
readonly tenantId: TenantId;
|
|
10
|
+
readonly runId: RunId;
|
|
11
|
+
/**
|
|
12
|
+
* The specs as asked — `QuestionSpec`, not a narrower copy of it (#163).
|
|
13
|
+
*
|
|
14
|
+
* This was an inline duplicate carrying only `key`, `prompt` and `options`, so when `multiple` and
|
|
15
|
+
* `allowOther` were added to `QuestionSpec` they were stored and read back by the adapters and then dropped
|
|
16
|
+
* on the floor here. Anything reading a pending question — the GraphQL query, a host's own UI — saw a
|
|
17
|
+
* multi-select as a single choice, with nothing in the types to say so.
|
|
18
|
+
*/
|
|
19
|
+
readonly questions: readonly QuestionSpec[];
|
|
20
|
+
readonly createdAt: string;
|
|
21
|
+
readonly answeredAt?: string;
|
|
22
|
+
/** A value may be a string or an array — see `QuestionSpec.multiple` (#155). */
|
|
23
|
+
readonly answers?: Readonly<Record<string, QuestionAnswer>>;
|
|
24
|
+
};
|
|
25
|
+
export declare const APPROVAL_DECISIONS: readonly ["allow-once", "allow-conversation", "allow-always", "deny"];
|
|
26
|
+
export type ApprovalDecision = (typeof APPROVAL_DECISIONS)[number];
|
|
27
|
+
export type ApprovalScope = "principal" | "tenant" | "category" | "conversation";
|
|
28
|
+
/**
|
|
29
|
+
* The pending approval stores the exact normalized tool name and input. Resumption
|
|
30
|
+
* executes the stored input — never a model-regenerated version.
|
|
31
|
+
*/
|
|
32
|
+
export type PendingApproval = {
|
|
33
|
+
readonly id: InteractionId;
|
|
34
|
+
readonly tenantId: TenantId;
|
|
35
|
+
readonly runId: RunId;
|
|
36
|
+
readonly toolName: string;
|
|
37
|
+
readonly normalizedInput: unknown;
|
|
38
|
+
readonly riskCategory: string;
|
|
39
|
+
readonly summary: string;
|
|
40
|
+
readonly estimatedCostMinorUnits?: number;
|
|
41
|
+
readonly expiresAt: string;
|
|
42
|
+
readonly idempotencyKey: string;
|
|
43
|
+
readonly decidedAt?: string;
|
|
44
|
+
readonly decision?: ApprovalDecision;
|
|
45
|
+
/**
|
|
46
|
+
* When the single execution this approval authorizes was claimed.
|
|
47
|
+
*
|
|
48
|
+
* This is where `allow-once` gets its "once". A grant would have been the easy mechanism and the
|
|
49
|
+
* wrong one — a grant is standing by definition, so issuing one for a one-time decision would
|
|
50
|
+
* silently broaden the authority the human actually gave. The interaction carries its own
|
|
51
|
+
* at-most-once counter instead, claimed atomically by the store, so a resumed run executes the
|
|
52
|
+
* approved call exactly once and a second attempt finds nothing left to claim.
|
|
53
|
+
*/
|
|
54
|
+
readonly consumedAt?: string;
|
|
55
|
+
};
|
|
56
|
+
/** A standing grant from `allow-conversation` or `allow-always`. */
|
|
57
|
+
export type ApprovalGrant = {
|
|
58
|
+
readonly id: ApprovalGrantId;
|
|
59
|
+
readonly tenantId: TenantId;
|
|
60
|
+
readonly scope: ApprovalScope;
|
|
61
|
+
readonly toolNameOrCategory: string;
|
|
62
|
+
/** Required when `scope` is `conversation`: the grant only applies within this conversation. */
|
|
63
|
+
readonly conversationId?: string;
|
|
64
|
+
readonly grantedAt: string;
|
|
65
|
+
readonly expiresAt?: string;
|
|
66
|
+
readonly revokedAt?: string;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Derived from tenant, run and tool-call identity, so a resumed or retried call returns
|
|
70
|
+
* the original result instead of repeating the side effect.
|
|
71
|
+
*/
|
|
72
|
+
export type IdempotencyKeyInput = {
|
|
73
|
+
readonly tenantId: TenantId;
|
|
74
|
+
readonly runId: RunId;
|
|
75
|
+
readonly toolCallId: string;
|
|
76
|
+
};
|
|
77
|
+
export * from "./service.js";
|
|
78
|
+
export * from "./approved-execution.js";
|
|
79
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable questions and approvals — `docs/04-durable-runtime-and-hitl.md`.
|
|
3
|
+
*/
|
|
4
|
+
export const APPROVAL_DECISIONS = [
|
|
5
|
+
"allow-once",
|
|
6
|
+
"allow-conversation",
|
|
7
|
+
"allow-always",
|
|
8
|
+
"deny",
|
|
9
|
+
];
|
|
10
|
+
export * from "./service.js";
|
|
11
|
+
export * from "./approved-execution.js";
|
|
12
|
+
//# sourceMappingURL=index.js.map
|