@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,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning stored attachments into turn parts — REQ-036 (#185), AC-3.
|
|
3
|
+
*
|
|
4
|
+
* `TurnContentPart` carries bytes or a URL, never a platform file id: the SDK boundary knows nothing about the
|
|
5
|
+
* file store. Something has to bridge the two, and that something is the place where a modality bridge either
|
|
6
|
+
* respects file authorization or quietly becomes a way around it.
|
|
7
|
+
*
|
|
8
|
+
* So this reads through `FileService` — the same call `read_attachment` makes, not the stores underneath it.
|
|
9
|
+
* Entitlement, existence and state all come from the service, so a turn cannot carry a file the person could not
|
|
10
|
+
* have opened. That is not a convention here; it is the only read path this module has.
|
|
11
|
+
*
|
|
12
|
+
* ## What it refuses, and why each one is a refusal rather than a silence
|
|
13
|
+
*
|
|
14
|
+
* Every skip comes back with a reason, and the caller is expected to say so in the transcript. A dropped
|
|
15
|
+
* attachment that nobody mentions is the worst outcome available: the person sees their screenshot in the
|
|
16
|
+
* thread, the model never received it, and the answer reads as though the model looked and disagreed.
|
|
17
|
+
*
|
|
18
|
+
* - **A media type the model cannot take.** Sending a `.docx` as an image part produces a provider error at best
|
|
19
|
+
* and a confidently wrong answer at worst.
|
|
20
|
+
* - **A file over the byte ceiling.** Base64 inflates by a third, and an image is a single indivisible part —
|
|
21
|
+
* there is no paging a picture. A 20MB photo is a request that fails after the money is spent.
|
|
22
|
+
* - **More attachments than the ceiling.** Ten images in one turn is a context window, not a question.
|
|
23
|
+
* - **A file the caller may not read.** `FileService.get` throws; the throw is caught and reported as a skip, so
|
|
24
|
+
* one inaccessible attachment does not fail a turn that had three others.
|
|
25
|
+
*/
|
|
26
|
+
import type { ExecutionContext } from "../core/context.js";
|
|
27
|
+
import type { FileService } from "./index.js";
|
|
28
|
+
import type { InputModality } from "../models/index.js";
|
|
29
|
+
import type { TurnContentPart } from "../models/streaming.js";
|
|
30
|
+
/**
|
|
31
|
+
* Media types that may travel as an image part, by modality.
|
|
32
|
+
*
|
|
33
|
+
* An allow-list, not a `image/*` wildcard — the same choice `read_attachment` makes for text. A wildcard admits
|
|
34
|
+
* every future format a provider does not accept, and the failure arrives from the provider as a 400 nobody can
|
|
35
|
+
* act on. `image/svg+xml` is deliberately absent: an SVG is a document that can fetch, and a model asked to
|
|
36
|
+
* "look at" one is being handed markup.
|
|
37
|
+
*/
|
|
38
|
+
export declare const IMAGE_PART_MEDIA_TYPES: readonly ["image/png", "image/jpeg", "image/webp", "image/gif"];
|
|
39
|
+
/** PDFs travel as a file part where the model accepts the `pdf` modality. */
|
|
40
|
+
export declare const FILE_PART_MEDIA_TYPES: readonly ["application/pdf"];
|
|
41
|
+
/**
|
|
42
|
+
* The per-attachment ceiling.
|
|
43
|
+
*
|
|
44
|
+
* Smaller than `read_attachment`'s 32KB window is *larger*, not smaller, and the difference is the point: text
|
|
45
|
+
* can be paged, so its tool reads a window. An image cannot be paged, so the whole thing travels or none of it
|
|
46
|
+
* does — and the ceiling is what stops "the whole thing" from being 20MB.
|
|
47
|
+
*/
|
|
48
|
+
export declare const MAX_ATTACHMENT_PART_BYTES: number;
|
|
49
|
+
/** How many attachments one turn may carry. Ten images is a context window, not a question. */
|
|
50
|
+
export declare const MAX_ATTACHMENT_PARTS = 4;
|
|
51
|
+
export type SkippedAttachment = {
|
|
52
|
+
readonly fileId: string;
|
|
53
|
+
readonly filename?: string;
|
|
54
|
+
/** `unreadable` covers both "does not exist" and "not yours" — the service does not distinguish, deliberately. */
|
|
55
|
+
readonly reason: "unsupported-media-type" | "too-large" | "too-many" | "unreadable" | "modality-not-accepted";
|
|
56
|
+
/** A sentence the caller can put in the transcript verbatim. */
|
|
57
|
+
readonly message: string;
|
|
58
|
+
};
|
|
59
|
+
export type ResolvedAttachments = {
|
|
60
|
+
readonly parts: readonly TurnContentPart[];
|
|
61
|
+
/**
|
|
62
|
+
* What did not make it, and why.
|
|
63
|
+
*
|
|
64
|
+
* Never empty-and-silent: a caller that ignores this is a caller whose users watch their attachment vanish.
|
|
65
|
+
*/
|
|
66
|
+
readonly skipped: readonly SkippedAttachment[];
|
|
67
|
+
};
|
|
68
|
+
export type AttachmentResolverDeps = {
|
|
69
|
+
readonly files: FileService;
|
|
70
|
+
readonly maxBytes?: number;
|
|
71
|
+
readonly maxParts?: number;
|
|
72
|
+
};
|
|
73
|
+
export type ResolveInput = {
|
|
74
|
+
readonly fileIds: readonly string[];
|
|
75
|
+
/**
|
|
76
|
+
* What the resolved model accepts.
|
|
77
|
+
*
|
|
78
|
+
* Passed in rather than looked up, because the model is chosen by the caller and this module has no registry.
|
|
79
|
+
* Omitted means "do not filter" — which is only correct when the caller applies `modelModalities` to the turn
|
|
80
|
+
* afterwards, and `streamModelTurn` does exactly that. Both checks existing is not redundancy: this one can
|
|
81
|
+
* say *which file* was dropped, and that one can only refuse the whole turn.
|
|
82
|
+
*/
|
|
83
|
+
readonly accepts?: readonly InputModality[];
|
|
84
|
+
};
|
|
85
|
+
export type AttachmentResolver = {
|
|
86
|
+
resolve(context: ExecutionContext, input: ResolveInput): Promise<ResolvedAttachments>;
|
|
87
|
+
};
|
|
88
|
+
export declare const createAttachmentResolver: (deps: AttachmentResolverDeps) => AttachmentResolver;
|
|
89
|
+
/**
|
|
90
|
+
* The sentence a caller puts in the transcript when something was left out.
|
|
91
|
+
*
|
|
92
|
+
* Provided rather than left to each host, because "say so in the transcript" is the half of AC-2 that a host
|
|
93
|
+
* forgets: the parts arrive, the turn works, and the skip is a field nobody read. One sentence, already written.
|
|
94
|
+
*/
|
|
95
|
+
export declare const describeSkipped: (skipped: readonly SkippedAttachment[]) => string | null;
|
|
96
|
+
//# sourceMappingURL=turn-parts.d.ts.map
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning stored attachments into turn parts — REQ-036 (#185), AC-3.
|
|
3
|
+
*
|
|
4
|
+
* `TurnContentPart` carries bytes or a URL, never a platform file id: the SDK boundary knows nothing about the
|
|
5
|
+
* file store. Something has to bridge the two, and that something is the place where a modality bridge either
|
|
6
|
+
* respects file authorization or quietly becomes a way around it.
|
|
7
|
+
*
|
|
8
|
+
* So this reads through `FileService` — the same call `read_attachment` makes, not the stores underneath it.
|
|
9
|
+
* Entitlement, existence and state all come from the service, so a turn cannot carry a file the person could not
|
|
10
|
+
* have opened. That is not a convention here; it is the only read path this module has.
|
|
11
|
+
*
|
|
12
|
+
* ## What it refuses, and why each one is a refusal rather than a silence
|
|
13
|
+
*
|
|
14
|
+
* Every skip comes back with a reason, and the caller is expected to say so in the transcript. A dropped
|
|
15
|
+
* attachment that nobody mentions is the worst outcome available: the person sees their screenshot in the
|
|
16
|
+
* thread, the model never received it, and the answer reads as though the model looked and disagreed.
|
|
17
|
+
*
|
|
18
|
+
* - **A media type the model cannot take.** Sending a `.docx` as an image part produces a provider error at best
|
|
19
|
+
* and a confidently wrong answer at worst.
|
|
20
|
+
* - **A file over the byte ceiling.** Base64 inflates by a third, and an image is a single indivisible part —
|
|
21
|
+
* there is no paging a picture. A 20MB photo is a request that fails after the money is spent.
|
|
22
|
+
* - **More attachments than the ceiling.** Ten images in one turn is a context window, not a question.
|
|
23
|
+
* - **A file the caller may not read.** `FileService.get` throws; the throw is caught and reported as a skip, so
|
|
24
|
+
* one inaccessible attachment does not fail a turn that had three others.
|
|
25
|
+
*/
|
|
26
|
+
import { AgentPlatformError } from "../core/errors.js";
|
|
27
|
+
import { asId } from "../core/ids.js";
|
|
28
|
+
/**
|
|
29
|
+
* Media types that may travel as an image part, by modality.
|
|
30
|
+
*
|
|
31
|
+
* An allow-list, not a `image/*` wildcard — the same choice `read_attachment` makes for text. A wildcard admits
|
|
32
|
+
* every future format a provider does not accept, and the failure arrives from the provider as a 400 nobody can
|
|
33
|
+
* act on. `image/svg+xml` is deliberately absent: an SVG is a document that can fetch, and a model asked to
|
|
34
|
+
* "look at" one is being handed markup.
|
|
35
|
+
*/
|
|
36
|
+
export const IMAGE_PART_MEDIA_TYPES = ["image/png", "image/jpeg", "image/webp", "image/gif"];
|
|
37
|
+
/** PDFs travel as a file part where the model accepts the `pdf` modality. */
|
|
38
|
+
export const FILE_PART_MEDIA_TYPES = ["application/pdf"];
|
|
39
|
+
/**
|
|
40
|
+
* The per-attachment ceiling.
|
|
41
|
+
*
|
|
42
|
+
* Smaller than `read_attachment`'s 32KB window is *larger*, not smaller, and the difference is the point: text
|
|
43
|
+
* can be paged, so its tool reads a window. An image cannot be paged, so the whole thing travels or none of it
|
|
44
|
+
* does — and the ceiling is what stops "the whole thing" from being 20MB.
|
|
45
|
+
*/
|
|
46
|
+
export const MAX_ATTACHMENT_PART_BYTES = 4 * 1024 * 1024;
|
|
47
|
+
/** How many attachments one turn may carry. Ten images is a context window, not a question. */
|
|
48
|
+
export const MAX_ATTACHMENT_PARTS = 4;
|
|
49
|
+
const modalityFor = (mediaType) => {
|
|
50
|
+
const type = mediaType.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
51
|
+
if (IMAGE_PART_MEDIA_TYPES.includes(type))
|
|
52
|
+
return "image";
|
|
53
|
+
if (FILE_PART_MEDIA_TYPES.includes(type))
|
|
54
|
+
return "pdf";
|
|
55
|
+
return undefined;
|
|
56
|
+
};
|
|
57
|
+
export const createAttachmentResolver = (deps) => {
|
|
58
|
+
const maxBytes = deps.maxBytes ?? MAX_ATTACHMENT_PART_BYTES;
|
|
59
|
+
const maxParts = deps.maxParts ?? MAX_ATTACHMENT_PARTS;
|
|
60
|
+
return {
|
|
61
|
+
async resolve(context, input) {
|
|
62
|
+
const parts = [];
|
|
63
|
+
const skipped = [];
|
|
64
|
+
for (const raw of input.fileIds) {
|
|
65
|
+
const fileId = raw.replace(/^file:/, "");
|
|
66
|
+
if (parts.length >= maxParts) {
|
|
67
|
+
skipped.push({
|
|
68
|
+
fileId,
|
|
69
|
+
reason: "too-many",
|
|
70
|
+
message: `Only ${maxParts} attachments can travel with one message; this one was left out.`,
|
|
71
|
+
});
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
let file;
|
|
75
|
+
try {
|
|
76
|
+
// Through the service, so entitlement, existence and state are its answer and not ours.
|
|
77
|
+
file = await deps.files.get(context, asId(fileId));
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
skipped.push({
|
|
81
|
+
fileId,
|
|
82
|
+
reason: "unreadable",
|
|
83
|
+
// Deliberately not distinguishing "missing" from "not yours": the service does not, because saying
|
|
84
|
+
// which would tell a caller that a file they cannot read exists.
|
|
85
|
+
message: error instanceof AgentPlatformError && error.code === "not_found"
|
|
86
|
+
? "That attachment could not be read."
|
|
87
|
+
: "That attachment could not be read.",
|
|
88
|
+
});
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const modality = modalityFor(file.mediaType);
|
|
92
|
+
if (modality === undefined) {
|
|
93
|
+
skipped.push({
|
|
94
|
+
fileId,
|
|
95
|
+
filename: file.filename,
|
|
96
|
+
reason: "unsupported-media-type",
|
|
97
|
+
message: `${file.filename} is ${file.mediaType}, which cannot be shown to a model directly. Read it with a tool instead.`,
|
|
98
|
+
});
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (input.accepts !== undefined && !input.accepts.includes(modality)) {
|
|
102
|
+
skipped.push({
|
|
103
|
+
fileId,
|
|
104
|
+
filename: file.filename,
|
|
105
|
+
reason: "modality-not-accepted",
|
|
106
|
+
message: `${file.filename} is ${modality}, which the selected model does not accept.`,
|
|
107
|
+
});
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (file.byteSize > maxBytes) {
|
|
111
|
+
skipped.push({
|
|
112
|
+
fileId,
|
|
113
|
+
filename: file.filename,
|
|
114
|
+
reason: "too-large",
|
|
115
|
+
// The number, so the sentence is actionable rather than a policy statement.
|
|
116
|
+
message: `${file.filename} is ${Math.round(file.byteSize / 1024)}KB, over the ` +
|
|
117
|
+
`${Math.round(maxBytes / 1024)}KB limit for an attachment sent to a model. An image cannot be ` +
|
|
118
|
+
`read in pages, so it travels whole or not at all.`,
|
|
119
|
+
});
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Read to the ceiling and *stop*, then check.
|
|
124
|
+
*
|
|
125
|
+
* `byteSize` is metadata, and metadata can disagree with the object — a truncated upload, a store
|
|
126
|
+
* someone wrote to directly. Reading with its own bound means a file that lies about its size costs the
|
|
127
|
+
* ceiling rather than whatever it actually is.
|
|
128
|
+
*/
|
|
129
|
+
const chunks = [];
|
|
130
|
+
let read = 0;
|
|
131
|
+
let overflowed = false;
|
|
132
|
+
for await (const chunk of await deps.files.read(context, asId(fileId))) {
|
|
133
|
+
read += chunk.byteLength;
|
|
134
|
+
if (read > maxBytes) {
|
|
135
|
+
overflowed = true;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
chunks.push(chunk);
|
|
139
|
+
}
|
|
140
|
+
if (overflowed) {
|
|
141
|
+
skipped.push({
|
|
142
|
+
fileId,
|
|
143
|
+
filename: file.filename,
|
|
144
|
+
reason: "too-large",
|
|
145
|
+
message: `${file.filename} is larger than its recorded size and over the attachment limit.`,
|
|
146
|
+
});
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const bytes = Buffer.concat(chunks.map((c) => Buffer.from(c)));
|
|
150
|
+
const data = `data:${file.mediaType};base64,${bytes.toString("base64")}`;
|
|
151
|
+
parts.push(modality === "image"
|
|
152
|
+
? { kind: "image", image: data, mediaType: file.mediaType }
|
|
153
|
+
: { kind: "file", data, mediaType: file.mediaType, filename: file.filename });
|
|
154
|
+
}
|
|
155
|
+
return { parts, skipped };
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* The sentence a caller puts in the transcript when something was left out.
|
|
161
|
+
*
|
|
162
|
+
* Provided rather than left to each host, because "say so in the transcript" is the half of AC-2 that a host
|
|
163
|
+
* forgets: the parts arrive, the turn works, and the skip is a field nobody read. One sentence, already written.
|
|
164
|
+
*/
|
|
165
|
+
export const describeSkipped = (skipped) => {
|
|
166
|
+
if (skipped.length === 0)
|
|
167
|
+
return null;
|
|
168
|
+
const lines = skipped.map((s) => `- ${s.message}`);
|
|
169
|
+
return `Some attachments were not sent to the model:\n${lines.join("\n")}`;
|
|
170
|
+
};
|
|
171
|
+
//# sourceMappingURL=turn-parts.js.map
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flows and teams — REQ-038 (#187) and REQ-037 (#186).
|
|
3
|
+
*
|
|
4
|
+
* Designed as one thing because both issues say so, and they are right: a flow's step and a team's member turn
|
|
5
|
+
* are the same idea, and modelling them separately produces two overlapping notions of "a step" that then have to
|
|
6
|
+
* be kept in agreement forever. So **a team is a kind of step**, and a team's members execute steps.
|
|
7
|
+
*
|
|
8
|
+
* ## The one design decision everything else follows from
|
|
9
|
+
*
|
|
10
|
+
* **The interpreter is a pure function.** `advance(definition, execution, outcome)` returns the next execution
|
|
11
|
+
* state and *one effect to perform* — it performs nothing itself. Every property these two REQs ask for falls out
|
|
12
|
+
* of that rather than being arranged separately:
|
|
13
|
+
*
|
|
14
|
+
* - **Durability** is persisting the returned state. There is no in-flight interpreter state to lose, because
|
|
15
|
+
* there is no interpreter instance.
|
|
16
|
+
* - **Resume after a restart** is loading the state and asking for the effect again. A host does not have to
|
|
17
|
+
* reconstruct where it was; the state *is* where it was.
|
|
18
|
+
* - **Idempotency across a resume** works because the effect carries a key derived from the execution and step,
|
|
19
|
+
* not from a counter in memory. A step that wrote externally and then crashed produces the same key on resume,
|
|
20
|
+
* and the idempotency store answers with the stored result.
|
|
21
|
+
* - **Testing** is exhaustive without mocks: feeding outcomes to a function and asserting the next state needs no
|
|
22
|
+
* agent, no database and no clock.
|
|
23
|
+
*
|
|
24
|
+
* The alternative — an async interpreter that awaits its own effects — is shorter to write and cannot be made
|
|
25
|
+
* durable without a checkpoint after every await, which is the same state machine with the states implicit.
|
|
26
|
+
*
|
|
27
|
+
* ## A definition and an execution are different things
|
|
28
|
+
*
|
|
29
|
+
* `FlowExecution.flowVersion` is pinned when the execution starts, and the definition is read at that version
|
|
30
|
+
* forever. Editing a flow does not change one already running. Conflating them is how a running automation
|
|
31
|
+
* silently changes shape halfway through — the person who edited step 4 has no idea an execution is sitting at
|
|
32
|
+
* step 3.
|
|
33
|
+
*/
|
|
34
|
+
import type { AgentId, ConversationId, PrincipalId, RunId, TenantId } from "../core/ids.js";
|
|
35
|
+
/**
|
|
36
|
+
* What a flow or a team may spend before it is stopped.
|
|
37
|
+
*
|
|
38
|
+
* Three dimensions because they fail differently, and a ceiling on one says nothing about the others. Steps bound
|
|
39
|
+
* a loop that makes no progress. Cost bounds a loop that makes expensive progress. Wall-clock bounds a step that
|
|
40
|
+
* hangs, which neither of the others catches — a flow waiting on a webhook consumes no steps and no money.
|
|
41
|
+
*/
|
|
42
|
+
export type FlowBudget = {
|
|
43
|
+
readonly maxSteps: number;
|
|
44
|
+
readonly maxCostMinorUnits?: number;
|
|
45
|
+
readonly maxWallClockMs?: number;
|
|
46
|
+
};
|
|
47
|
+
/** Spent so far. Compared against the budget before every step, never after. */
|
|
48
|
+
export type FlowSpend = {
|
|
49
|
+
readonly steps: number;
|
|
50
|
+
readonly costMinorUnits: number;
|
|
51
|
+
readonly startedAtMs: number;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* What happens when a step fails — chosen in the definition, not by whichever error surfaced.
|
|
55
|
+
*
|
|
56
|
+
* `escalate` is the one worth explaining: it hands the failure to the enclosing scope rather than deciding here. A
|
|
57
|
+
* team member escalates to its manager; a flow step escalates to its parent flow. Without it, "retry or die" is
|
|
58
|
+
* the whole vocabulary, and a manager-led team cannot react to a member failing, which is most of the point of
|
|
59
|
+
* having a manager.
|
|
60
|
+
*/
|
|
61
|
+
export declare const FAILURE_ACTIONS: readonly ["retry", "skip", "escalate", "fail"];
|
|
62
|
+
export type FailureAction = (typeof FAILURE_ACTIONS)[number];
|
|
63
|
+
export type FailurePolicy = {
|
|
64
|
+
readonly action: FailureAction;
|
|
65
|
+
/** Only meaningful for `retry`. Bounded, because an unbounded retry is a loop with a good excuse. */
|
|
66
|
+
readonly maxAttempts?: number;
|
|
67
|
+
/** Milliseconds before the first retry; doubles each attempt. */
|
|
68
|
+
readonly backoffMs?: number;
|
|
69
|
+
};
|
|
70
|
+
export declare const DEFAULT_FAILURE_POLICY: FailurePolicy;
|
|
71
|
+
/**
|
|
72
|
+
* A reference into the execution's state, for a step's input and a branch's condition.
|
|
73
|
+
*
|
|
74
|
+
* A path, not an expression. `"$.order.total"` reads a value; there is no arithmetic, no comparison operators and
|
|
75
|
+
* no function calls, because an expression language in a stored definition is an interpreter that runs whatever a
|
|
76
|
+
* definition author typed — and the definitions will eventually be authored in a UI by someone who is not an
|
|
77
|
+
* engineer (REQ-042). Comparison lives in the *branch*, which has a closed set of operators.
|
|
78
|
+
*/
|
|
79
|
+
export type StatePath = string;
|
|
80
|
+
export declare const BRANCH_OPERATORS: readonly ["equals", "not-equals", "exists", "absent", "greater-than", "less-than", "contains"];
|
|
81
|
+
export type BranchOperator = (typeof BRANCH_OPERATORS)[number];
|
|
82
|
+
export type BranchCase = {
|
|
83
|
+
readonly path: StatePath;
|
|
84
|
+
readonly operator: BranchOperator;
|
|
85
|
+
/** Absent for `exists` and `absent`, which are about presence rather than value. */
|
|
86
|
+
readonly value?: string | number | boolean;
|
|
87
|
+
readonly next: string;
|
|
88
|
+
};
|
|
89
|
+
export declare const STEP_KINDS: readonly ["agent", "team", "tool", "branch", "wait", "checkpoint", "subflow", "done"];
|
|
90
|
+
export type StepKind = (typeof STEP_KINDS)[number];
|
|
91
|
+
type StepBase = {
|
|
92
|
+
readonly name: string;
|
|
93
|
+
readonly onFailure?: FailurePolicy;
|
|
94
|
+
/**
|
|
95
|
+
* Where the step's result is written in the execution state.
|
|
96
|
+
*
|
|
97
|
+
* Absent means the result is discarded, which is a real choice: a step whose output nothing reads should say so,
|
|
98
|
+
* rather than accumulating state a later reader has to guess the relevance of.
|
|
99
|
+
*/
|
|
100
|
+
readonly assignTo?: string;
|
|
101
|
+
};
|
|
102
|
+
export type FlowStep = (StepBase & {
|
|
103
|
+
readonly kind: "agent";
|
|
104
|
+
readonly agentId: AgentId;
|
|
105
|
+
/** Appended to the agent's own instructions for this step only. */
|
|
106
|
+
readonly instructions?: string;
|
|
107
|
+
/** What the agent is asked, with `{{path}}` interpolated from state. */
|
|
108
|
+
readonly prompt: string;
|
|
109
|
+
readonly next?: string;
|
|
110
|
+
}) | (StepBase & {
|
|
111
|
+
readonly kind: "team";
|
|
112
|
+
readonly teamId: string;
|
|
113
|
+
readonly prompt: string;
|
|
114
|
+
readonly next?: string;
|
|
115
|
+
}) | (StepBase & {
|
|
116
|
+
readonly kind: "tool";
|
|
117
|
+
readonly tool: string;
|
|
118
|
+
/** Literal values, or `{{path}}` references resolved from state. */
|
|
119
|
+
readonly input: Readonly<Record<string, unknown>>;
|
|
120
|
+
readonly next?: string;
|
|
121
|
+
}) | (StepBase & {
|
|
122
|
+
readonly kind: "branch";
|
|
123
|
+
readonly cases: readonly BranchCase[];
|
|
124
|
+
readonly otherwise?: string;
|
|
125
|
+
}) | (StepBase & {
|
|
126
|
+
readonly kind: "wait";
|
|
127
|
+
/** A duration, or a named signal something outside the flow delivers. */
|
|
128
|
+
readonly forMs?: number;
|
|
129
|
+
readonly forSignal?: string;
|
|
130
|
+
readonly next?: string;
|
|
131
|
+
}) | (StepBase & {
|
|
132
|
+
readonly kind: "checkpoint";
|
|
133
|
+
/** Asked through the existing HITL path, so a parked flow is the object the assistant surface already answers. */
|
|
134
|
+
readonly question: string;
|
|
135
|
+
readonly options?: readonly string[];
|
|
136
|
+
readonly next?: string;
|
|
137
|
+
}) | (StepBase & {
|
|
138
|
+
readonly kind: "subflow";
|
|
139
|
+
readonly flowId: string;
|
|
140
|
+
readonly next?: string;
|
|
141
|
+
}) | (StepBase & {
|
|
142
|
+
readonly kind: "done";
|
|
143
|
+
readonly outcome?: string;
|
|
144
|
+
});
|
|
145
|
+
export type FlowDefinition = {
|
|
146
|
+
readonly id: string;
|
|
147
|
+
/** Immutable per version. An execution pins one and reads it forever — see the module comment. */
|
|
148
|
+
readonly version: number;
|
|
149
|
+
readonly name: string;
|
|
150
|
+
readonly description?: string;
|
|
151
|
+
readonly steps: readonly FlowStep[];
|
|
152
|
+
readonly start: string;
|
|
153
|
+
readonly budget: FlowBudget;
|
|
154
|
+
/**
|
|
155
|
+
* How deep a subflow or a team may nest.
|
|
156
|
+
*
|
|
157
|
+
* Enforced rather than documented, and it is what makes A → B → A terminate: each level carries its depth, and
|
|
158
|
+
* a step that would exceed the bound fails the flow with a message naming the chain. A cycle detector over the
|
|
159
|
+
* definition graph would not be enough, because a subflow reference is resolved at run time and the graph is
|
|
160
|
+
* only known then.
|
|
161
|
+
*/
|
|
162
|
+
readonly maxDepth?: number;
|
|
163
|
+
};
|
|
164
|
+
export declare const DEFAULT_MAX_DEPTH = 5;
|
|
165
|
+
/** One member of a team. Its own instructions, its own tools, its own limits. */
|
|
166
|
+
export type TeamMember = {
|
|
167
|
+
readonly name: string;
|
|
168
|
+
readonly agentId: AgentId;
|
|
169
|
+
readonly instructions?: string;
|
|
170
|
+
/**
|
|
171
|
+
* Tool names this member may use, narrowing the team's own set.
|
|
172
|
+
*
|
|
173
|
+
* A narrowing, never a widening: the delegation tool intersects this with what the delegating context could
|
|
174
|
+
* reach, so a member cannot be granted something the team was not. #186 AC-3 — "a delegated agent cannot reach
|
|
175
|
+
* a tool the delegating one could not" — is that intersection, and it is enforced where the tool set is built
|
|
176
|
+
* rather than checked afterwards.
|
|
177
|
+
*/
|
|
178
|
+
readonly tools?: readonly string[];
|
|
179
|
+
readonly maxSteps?: number;
|
|
180
|
+
};
|
|
181
|
+
export declare const TEAM_PROCESSES: readonly ["sequential", "manager-led"];
|
|
182
|
+
export type TeamProcess = (typeof TEAM_PROCESSES)[number];
|
|
183
|
+
export type TeamDefinition = {
|
|
184
|
+
readonly id: string;
|
|
185
|
+
readonly version: number;
|
|
186
|
+
readonly name: string;
|
|
187
|
+
/**
|
|
188
|
+
* Sequential or manager-led, as a **property** rather than two code paths — #186 AC-2.
|
|
189
|
+
*
|
|
190
|
+
* The interpreter branches on this in one place: which member runs next. Everything else — budgets, delegation,
|
|
191
|
+
* failure handling, attribution — is identical, which is the point. Two code paths would mean two places for
|
|
192
|
+
* every later property to be added, and one of them would eventually not get it.
|
|
193
|
+
*/
|
|
194
|
+
readonly process: TeamProcess;
|
|
195
|
+
readonly members: readonly TeamMember[];
|
|
196
|
+
/** Required when `process` is `manager-led`, and refused otherwise: a sequential team with a manager is ambiguous. */
|
|
197
|
+
readonly manager?: string;
|
|
198
|
+
readonly budget: FlowBudget;
|
|
199
|
+
readonly maxDelegationDepth?: number;
|
|
200
|
+
};
|
|
201
|
+
export declare const FLOW_STATUSES: readonly ["running", "waiting", "completed", "failed", "cancelled"];
|
|
202
|
+
export type FlowStatus = (typeof FLOW_STATUSES)[number];
|
|
203
|
+
export type StepRecord = {
|
|
204
|
+
readonly step: string;
|
|
205
|
+
readonly kind: StepKind;
|
|
206
|
+
readonly startedAt: string;
|
|
207
|
+
readonly finishedAt?: string;
|
|
208
|
+
readonly outcome: "ok" | "failed" | "skipped" | "waiting";
|
|
209
|
+
readonly attempt: number;
|
|
210
|
+
/** Which team member ran it, when a team step did — #186 AC-9, so "which agent costs the money" is answerable. */
|
|
211
|
+
readonly member?: string;
|
|
212
|
+
readonly costMinorUnits?: number;
|
|
213
|
+
readonly error?: string;
|
|
214
|
+
};
|
|
215
|
+
export type FlowExecution = {
|
|
216
|
+
readonly id: string;
|
|
217
|
+
readonly tenantId: TenantId;
|
|
218
|
+
readonly flowId: string;
|
|
219
|
+
/** Pinned at start. The definition is read at this version for the execution's whole life. */
|
|
220
|
+
readonly flowVersion: number;
|
|
221
|
+
/** The platform run this execution is, so quotas, usage and events apply as they do to any run. */
|
|
222
|
+
readonly runId: RunId;
|
|
223
|
+
readonly principalId: PrincipalId;
|
|
224
|
+
readonly conversationId?: ConversationId;
|
|
225
|
+
readonly status: FlowStatus;
|
|
226
|
+
/** The step about to run, or the one being waited on. `null` once terminal. */
|
|
227
|
+
readonly currentStep: string | null;
|
|
228
|
+
/**
|
|
229
|
+
* State between steps, durable, and **readable by a person** — #187 AC-3.
|
|
230
|
+
*
|
|
231
|
+
* A flat JSON object rather than an opaque blob, because "what state is this flow in" is a question someone
|
|
232
|
+
* asks while it is stuck, and an answer they cannot read is not an answer.
|
|
233
|
+
*/
|
|
234
|
+
readonly state: Readonly<Record<string, unknown>>;
|
|
235
|
+
readonly spend: FlowSpend;
|
|
236
|
+
readonly history: readonly StepRecord[];
|
|
237
|
+
/** Attempts for the current step, so a retry policy survives a restart. */
|
|
238
|
+
readonly attempt: number;
|
|
239
|
+
readonly depth: number;
|
|
240
|
+
readonly startedAt: string;
|
|
241
|
+
readonly finishedAt?: string;
|
|
242
|
+
/** Why it stopped, when it stopped for a reason worth reading. */
|
|
243
|
+
readonly detail?: string;
|
|
244
|
+
/** Set while `waiting`: the interaction a checkpoint is parked on, or the signal a wait needs. */
|
|
245
|
+
readonly waitingFor?: {
|
|
246
|
+
readonly kind: "human";
|
|
247
|
+
readonly interactionId: string;
|
|
248
|
+
} | {
|
|
249
|
+
readonly kind: "signal";
|
|
250
|
+
readonly signal: string;
|
|
251
|
+
} | {
|
|
252
|
+
readonly kind: "time";
|
|
253
|
+
readonly untilMs: number;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* A child run — #202.
|
|
257
|
+
*
|
|
258
|
+
* An agent step is a run of its own, so the flow parks on it. The `runId` is stored rather than held, which
|
|
259
|
+
* is what makes both wake-up paths work: a notification when the child settles, and a *poll* on resume for
|
|
260
|
+
* when the notification never arrived. Depending only on the notification would be depending on a message
|
|
261
|
+
* that a crash between the child completing and the parent being told simply loses.
|
|
262
|
+
*/
|
|
263
|
+
| {
|
|
264
|
+
readonly kind: "run";
|
|
265
|
+
readonly runId: string;
|
|
266
|
+
readonly member?: string;
|
|
267
|
+
};
|
|
268
|
+
};
|
|
269
|
+
export {};
|
|
270
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flows and teams — REQ-038 (#187) and REQ-037 (#186).
|
|
3
|
+
*
|
|
4
|
+
* Designed as one thing because both issues say so, and they are right: a flow's step and a team's member turn
|
|
5
|
+
* are the same idea, and modelling them separately produces two overlapping notions of "a step" that then have to
|
|
6
|
+
* be kept in agreement forever. So **a team is a kind of step**, and a team's members execute steps.
|
|
7
|
+
*
|
|
8
|
+
* ## The one design decision everything else follows from
|
|
9
|
+
*
|
|
10
|
+
* **The interpreter is a pure function.** `advance(definition, execution, outcome)` returns the next execution
|
|
11
|
+
* state and *one effect to perform* — it performs nothing itself. Every property these two REQs ask for falls out
|
|
12
|
+
* of that rather than being arranged separately:
|
|
13
|
+
*
|
|
14
|
+
* - **Durability** is persisting the returned state. There is no in-flight interpreter state to lose, because
|
|
15
|
+
* there is no interpreter instance.
|
|
16
|
+
* - **Resume after a restart** is loading the state and asking for the effect again. A host does not have to
|
|
17
|
+
* reconstruct where it was; the state *is* where it was.
|
|
18
|
+
* - **Idempotency across a resume** works because the effect carries a key derived from the execution and step,
|
|
19
|
+
* not from a counter in memory. A step that wrote externally and then crashed produces the same key on resume,
|
|
20
|
+
* and the idempotency store answers with the stored result.
|
|
21
|
+
* - **Testing** is exhaustive without mocks: feeding outcomes to a function and asserting the next state needs no
|
|
22
|
+
* agent, no database and no clock.
|
|
23
|
+
*
|
|
24
|
+
* The alternative — an async interpreter that awaits its own effects — is shorter to write and cannot be made
|
|
25
|
+
* durable without a checkpoint after every await, which is the same state machine with the states implicit.
|
|
26
|
+
*
|
|
27
|
+
* ## A definition and an execution are different things
|
|
28
|
+
*
|
|
29
|
+
* `FlowExecution.flowVersion` is pinned when the execution starts, and the definition is read at that version
|
|
30
|
+
* forever. Editing a flow does not change one already running. Conflating them is how a running automation
|
|
31
|
+
* silently changes shape halfway through — the person who edited step 4 has no idea an execution is sitting at
|
|
32
|
+
* step 3.
|
|
33
|
+
*/
|
|
34
|
+
// ---------------------------------------------------------------------------------------------------
|
|
35
|
+
// Failure policy
|
|
36
|
+
// ---------------------------------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* What happens when a step fails — chosen in the definition, not by whichever error surfaced.
|
|
39
|
+
*
|
|
40
|
+
* `escalate` is the one worth explaining: it hands the failure to the enclosing scope rather than deciding here. A
|
|
41
|
+
* team member escalates to its manager; a flow step escalates to its parent flow. Without it, "retry or die" is
|
|
42
|
+
* the whole vocabulary, and a manager-led team cannot react to a member failing, which is most of the point of
|
|
43
|
+
* having a manager.
|
|
44
|
+
*/
|
|
45
|
+
export const FAILURE_ACTIONS = ["retry", "skip", "escalate", "fail"];
|
|
46
|
+
export const DEFAULT_FAILURE_POLICY = { action: "fail" };
|
|
47
|
+
export const BRANCH_OPERATORS = ["equals", "not-equals", "exists", "absent", "greater-than", "less-than", "contains"];
|
|
48
|
+
export const STEP_KINDS = ["agent", "team", "tool", "branch", "wait", "checkpoint", "subflow", "done"];
|
|
49
|
+
export const DEFAULT_MAX_DEPTH = 5;
|
|
50
|
+
export const TEAM_PROCESSES = ["sequential", "manager-led"];
|
|
51
|
+
// ---------------------------------------------------------------------------------------------------
|
|
52
|
+
// Execution
|
|
53
|
+
// ---------------------------------------------------------------------------------------------------
|
|
54
|
+
export const FLOW_STATUSES = [
|
|
55
|
+
"running",
|
|
56
|
+
/** Parked on a `checkpoint` or a `wait` for a signal. Not failed, and not finished. */
|
|
57
|
+
"waiting",
|
|
58
|
+
"completed",
|
|
59
|
+
"failed",
|
|
60
|
+
"cancelled",
|
|
61
|
+
];
|
|
62
|
+
//# sourceMappingURL=index.js.map
|