@dynamicagents/core 0.9.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 +201 -0
- package/README.md +522 -0
- package/dist/a2a/agent-stub.d.ts +60 -0
- package/dist/a2a/agent-stub.js +1 -0
- package/dist/a2a/caller-token.d.ts +44 -0
- package/dist/a2a/caller-token.js +61 -0
- package/dist/a2a/caller.d.ts +23 -0
- package/dist/a2a/caller.js +33 -0
- package/dist/a2a/card.d.ts +158 -0
- package/dist/a2a/card.js +163 -0
- package/dist/a2a/context.d.ts +19 -0
- package/dist/a2a/context.js +61 -0
- package/dist/a2a/deliver.d.ts +159 -0
- package/dist/a2a/deliver.js +185 -0
- package/dist/a2a/executor.d.ts +84 -0
- package/dist/a2a/executor.js +106 -0
- package/dist/a2a/index.d.ts +35 -0
- package/dist/a2a/index.js +34 -0
- package/dist/a2a/notify.d.ts +106 -0
- package/dist/a2a/notify.js +180 -0
- package/dist/a2a/parts.d.ts +45 -0
- package/dist/a2a/parts.js +94 -0
- package/dist/a2a/push.d.ts +70 -0
- package/dist/a2a/push.js +53 -0
- package/dist/a2a/self-origin.d.ts +91 -0
- package/dist/a2a/self-origin.js +114 -0
- package/dist/a2a/task-store.d.ts +44 -0
- package/dist/a2a/task-store.js +99 -0
- package/dist/a2a/task.d.ts +85 -0
- package/dist/a2a/task.js +15 -0
- package/dist/a2a/verify.d.ts +80 -0
- package/dist/a2a/verify.js +143 -0
- package/dist/agent/budget.d.ts +46 -0
- package/dist/agent/budget.js +42 -0
- package/dist/agent/control.d.ts +109 -0
- package/dist/agent/control.js +115 -0
- package/dist/agent/errors.d.ts +85 -0
- package/dist/agent/errors.js +64 -0
- package/dist/agent/final-reply.d.ts +49 -0
- package/dist/agent/final-reply.js +68 -0
- package/dist/agent/history.d.ts +97 -0
- package/dist/agent/history.js +133 -0
- package/dist/agent/index.d.ts +29 -0
- package/dist/agent/index.js +29 -0
- package/dist/agent/inference.d.ts +110 -0
- package/dist/agent/inference.js +120 -0
- package/dist/agent/model.d.ts +90 -0
- package/dist/agent/model.js +1 -0
- package/dist/agent/session.d.ts +100 -0
- package/dist/agent/session.js +82 -0
- package/dist/agent/workers-ai/index.d.ts +23 -0
- package/dist/agent/workers-ai/index.js +23 -0
- package/dist/agent/workers-ai/runtime.d.ts +42 -0
- package/dist/agent/workers-ai/runtime.js +63 -0
- package/dist/alarm/index.d.ts +77 -0
- package/dist/alarm/index.js +116 -0
- package/dist/config.d.ts +202 -0
- package/dist/config.js +135 -0
- package/dist/contract/index.d.ts +9 -0
- package/dist/contract/index.js +8 -0
- package/dist/contract/plugin.d.ts +324 -0
- package/dist/contract/plugin.js +114 -0
- package/dist/contract/recipe.d.ts +180 -0
- package/dist/contract/recipe.js +1 -0
- package/dist/contract/validation.d.ts +91 -0
- package/dist/contract/validation.js +84 -0
- package/dist/db/db.d.ts +147 -0
- package/dist/db/db.js +90 -0
- package/dist/db/index.d.ts +8 -0
- package/dist/db/index.js +8 -0
- package/dist/db/migrations/index.d.ts +20 -0
- package/dist/db/migrations/index.js +60 -0
- package/dist/db/models/subtasks.d.ts +100 -0
- package/dist/db/models/subtasks.js +241 -0
- package/dist/db/models/tasks.d.ts +118 -0
- package/dist/db/models/tasks.js +274 -0
- package/dist/db/schema.d.ts +468 -0
- package/dist/db/schema.js +88 -0
- package/dist/env.d.ts +53 -0
- package/dist/env.js +47 -0
- package/dist/host/agent.d.ts +305 -0
- package/dist/host/agent.js +400 -0
- package/dist/host/index.d.ts +20 -0
- package/dist/host/index.js +19 -0
- package/dist/host/plugin-host.d.ts +42 -0
- package/dist/host/plugin-host.js +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +17 -0
- package/dist/job/index.d.ts +21 -0
- package/dist/job/index.js +21 -0
- package/dist/job/lifecycle.d.ts +176 -0
- package/dist/job/lifecycle.js +230 -0
- package/dist/job/state.d.ts +92 -0
- package/dist/job/state.js +40 -0
- package/dist/platform.d.ts +138 -0
- package/dist/platform.js +140 -0
- package/dist/round/agent.d.ts +271 -0
- package/dist/round/agent.js +678 -0
- package/dist/round/index.d.ts +25 -0
- package/dist/round/index.js +23 -0
- package/dist/round/policy.d.ts +98 -0
- package/dist/round/policy.js +1 -0
- package/dist/round/subagent.d.ts +87 -0
- package/dist/round/subagent.js +108 -0
- package/dist/round/turn.d.ts +249 -0
- package/dist/round/turn.js +564 -0
- package/dist/round/workflow.d.ts +147 -0
- package/dist/round/workflow.js +387 -0
- package/dist/runtime/index.d.ts +127 -0
- package/dist/runtime/index.js +186 -0
- package/dist/runtime/tool-families.d.ts +32 -0
- package/dist/runtime/tool-families.js +61 -0
- package/dist/subagent/fingerprint.d.ts +37 -0
- package/dist/subagent/fingerprint.js +92 -0
- package/dist/subagent/index.d.ts +169 -0
- package/dist/subagent/index.js +330 -0
- package/dist/subagent/prompt.d.ts +32 -0
- package/dist/subagent/prompt.js +37 -0
- package/dist/subagent/run.d.ts +157 -0
- package/dist/subagent/run.js +540 -0
- package/dist/subagent/workspace.d.ts +85 -0
- package/dist/subagent/workspace.js +127 -0
- package/dist/subtasks/catalog.d.ts +40 -0
- package/dist/subtasks/catalog.js +36 -0
- package/dist/subtasks/decomposition.d.ts +85 -0
- package/dist/subtasks/decomposition.js +156 -0
- package/dist/subtasks/delegate.d.ts +120 -0
- package/dist/subtasks/delegate.js +131 -0
- package/dist/subtasks/index.d.ts +9 -0
- package/dist/subtasks/index.js +9 -0
- package/dist/subtasks/subtask-types.d.ts +91 -0
- package/dist/subtasks/subtask-types.js +103 -0
- package/dist/subtasks/types.d.ts +295 -0
- package/dist/subtasks/types.js +15 -0
- package/dist/testing/auth.d.ts +34 -0
- package/dist/testing/auth.js +35 -0
- package/dist/testing/do.d.ts +29 -0
- package/dist/testing/do.js +25 -0
- package/dist/testing/fake-session.d.ts +26 -0
- package/dist/testing/fake-session.js +37 -0
- package/dist/testing/fixtures.d.ts +64 -0
- package/dist/testing/fixtures.js +104 -0
- package/dist/testing/harness.d.ts +97 -0
- package/dist/testing/harness.js +138 -0
- package/dist/testing/index.d.ts +31 -0
- package/dist/testing/index.js +35 -0
- package/dist/testing/mock-model.d.ts +77 -0
- package/dist/testing/mock-model.js +136 -0
- package/dist/testing/node.d.ts +56 -0
- package/dist/testing/node.js +56 -0
- package/dist/testing/vcr-global-setup.d.ts +12 -0
- package/dist/testing/vcr-global-setup.js +15 -0
- package/dist/testing/vcr-shared.d.ts +38 -0
- package/dist/testing/vcr-shared.js +33 -0
- package/dist/testing/vcr-spec.d.ts +25 -0
- package/dist/testing/vcr-spec.js +124 -0
- package/dist/testing/vcr-store.d.ts +86 -0
- package/dist/testing/vcr-store.js +191 -0
- package/dist/testing/vcr.d.ts +117 -0
- package/dist/testing/vcr.js +275 -0
- package/dist/worker/define-agent.d.ts +123 -0
- package/dist/worker/define-agent.js +20 -0
- package/dist/worker/index.d.ts +218 -0
- package/dist/worker/index.js +369 -0
- package/eslint-rules/index.js +31 -0
- package/eslint-rules/no-deprecated-object-properties.js +81 -0
- package/package.json +178 -0
- package/scripts/generate-keys.mjs +48 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { Agent, type Schedule } from "agents";
|
|
2
|
+
import { type Task } from "@a2a-js/sdk";
|
|
3
|
+
import { type AgentRuntime } from "../runtime/index.js";
|
|
4
|
+
import type { AgentPlugin } from "../contract/plugin.js";
|
|
5
|
+
import { type CoreConfig, type CoreConfigOverrides, type ModelConfig } from "../config.js";
|
|
6
|
+
import type { A2ASecretsEnv, AiEnv } from "../env.js";
|
|
7
|
+
import { AgentDB } from "../db/index.js";
|
|
8
|
+
import type { GatekeeperIdentity } from "../a2a/verify.js";
|
|
9
|
+
import type { PlainTask } from "../a2a/task.js";
|
|
10
|
+
import type { TaskListQuery } from "../a2a/agent-stub.js";
|
|
11
|
+
import { type PushChannel, type TurnPushContext } from "../a2a/push.js";
|
|
12
|
+
import { type SessionLike } from "../agent/session.js";
|
|
13
|
+
import type { AiGatewayMetadata, ModelPair, ModelRuntime } from "../agent/model.js";
|
|
14
|
+
import type { PluginHost } from "./plugin-host.js";
|
|
15
|
+
/**
|
|
16
|
+
* The Durable Object body every Dynamic Agents agent has, whatever loop it runs.
|
|
17
|
+
*
|
|
18
|
+
* ## Why this is core's and not the app's
|
|
19
|
+
*
|
|
20
|
+
* It was the app's, in the starter, and it was written twice — once for the
|
|
21
|
+
* delegating round agent, once for the single-turn proactive one. The two copies
|
|
22
|
+
* were identical for ~180 lines: the memoized runtime/db/models getters, the
|
|
23
|
+
* `onStart` that must await migrations before the SDK dispatches any RPC, the
|
|
24
|
+
* cron registration guard, the session with its displacement fan-out, the
|
|
25
|
+
* `identityKey` timing, and the task RPC surface.
|
|
26
|
+
*
|
|
27
|
+
* They did not stay identical. The second copy dropped `markWorking`'s
|
|
28
|
+
* cancellation verdict on the floor and probed with a separate `getTask` before
|
|
29
|
+
* writing a terminal Task — so a canceled task still burned a model call, and the
|
|
30
|
+
* gatekeeper could still receive a `completed` callback for a task the caller had
|
|
31
|
+
* abandoned. Both are lifecycle invariants, both were documented in the first
|
|
32
|
+
* copy, and neither is visible to a type checker or a linter.
|
|
33
|
+
*
|
|
34
|
+
* That is the argument for this class. **None of it is policy.** How a turn is
|
|
35
|
+
* shaped, what ends it, what the model is told — all of that stays with the
|
|
36
|
+
* agent, and an agent that wants a different loop simply does not extend
|
|
37
|
+
* {@link file://../round/agent.ts RoundAgentBase}. What is here is the part where
|
|
38
|
+
* being different is only ever a bug.
|
|
39
|
+
*
|
|
40
|
+
* ## The three seams
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* export class MyAgent extends DynamicAgent<Env> {
|
|
44
|
+
* protected agentConfig() { return MY_CONFIG; }
|
|
45
|
+
* protected agentPlugins(host: PluginHost<Env>) { return plugins(host); }
|
|
46
|
+
* protected agentSoul(capabilities: string) { return soulPrompt(capabilities); }
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* One Durable Object instance per verified caller (keyed by the gatekeeper JWT's
|
|
51
|
+
* `identity.key`), each owning **one continuous Session** — durable history plus
|
|
52
|
+
* a self-edited `memory` block, backed by `this.sql`. All of a caller's turns, in
|
|
53
|
+
* any channel or thread, accumulate into that one conversation.
|
|
54
|
+
*/
|
|
55
|
+
export declare abstract class DynamicAgent<TEnv extends Cloudflare.Env & AiEnv & A2ASecretsEnv = Cloudflare.Env & AiEnv & A2ASecretsEnv> extends Agent<TEnv> {
|
|
56
|
+
private session?;
|
|
57
|
+
private _runtime?;
|
|
58
|
+
private _models?;
|
|
59
|
+
private _pair?;
|
|
60
|
+
private _db?;
|
|
61
|
+
/**
|
|
62
|
+
* The verified caller this instance belongs to, set on the first turn.
|
|
63
|
+
*
|
|
64
|
+
* `onStart` runs before any request, so it is not known when `agentPlugins()`
|
|
65
|
+
* is built — which is why anything per-caller takes a thunk. The DO is keyed
|
|
66
|
+
* 1:1 by this value, so it is constant once set.
|
|
67
|
+
*
|
|
68
|
+
* In-memory, and deliberately so — see {@link requireIdentityKey}, which does
|
|
69
|
+
* not depend on it surviving.
|
|
70
|
+
*/
|
|
71
|
+
private identityKey?;
|
|
72
|
+
/**
|
|
73
|
+
* This deployment's own public origin, learned from the `jku` every turn
|
|
74
|
+
* carries and **pinned on the first one** this instance serves.
|
|
75
|
+
*
|
|
76
|
+
* Unlike {@link identityKey} this is shared by concurrent turns — the object
|
|
77
|
+
* is keyed by caller, not by origin — so it is pinned rather than
|
|
78
|
+
* last-write-wins: an immutable field cannot change under a credential thunk
|
|
79
|
+
* that reads it while a turn awaits a model call. See {@link SelfOrigin} for
|
|
80
|
+
* the full argument, and for why nothing is persisted.
|
|
81
|
+
*/
|
|
82
|
+
private readonly selfOriginMemo;
|
|
83
|
+
/**
|
|
84
|
+
* Test-only model injection. A **field**, not a constructor argument or an RPC
|
|
85
|
+
* parameter, so it never appears on the generated DO stub: production callers
|
|
86
|
+
* cannot reach it, and no model configuration crosses the RPC boundary.
|
|
87
|
+
*/
|
|
88
|
+
modelsOverride?: ModelPair;
|
|
89
|
+
/** This agent's config overrides. Merged onto core's baseline once, at start. */
|
|
90
|
+
protected abstract agentConfig(): CoreConfigOverrides;
|
|
91
|
+
/** This agent's installed capabilities. Conventionally its `./plugins.ts`. */
|
|
92
|
+
protected abstract agentPlugins(host: PluginHost<TEnv>): AgentPlugin[];
|
|
93
|
+
/**
|
|
94
|
+
* This agent's identity, with the installed plugins' capability blocks already
|
|
95
|
+
* rendered in. Core ships no prompt copy — this is yours to write.
|
|
96
|
+
*/
|
|
97
|
+
protected abstract agentSoul(capabilities: string): string;
|
|
98
|
+
/**
|
|
99
|
+
* Everything that would otherwise be a module-level constant, resolved once
|
|
100
|
+
* per DO instance from this agent's config and its installed plugins.
|
|
101
|
+
*
|
|
102
|
+
* Resolving a registry at *import* time is the one thing the package split
|
|
103
|
+
* exists to prevent: it freezes the registry before `env` exists (which on
|
|
104
|
+
* Workers is always), defeats tree-shaking, and makes per-agent plugin
|
|
105
|
+
* selection impossible.
|
|
106
|
+
*/
|
|
107
|
+
protected get runtime(): AgentRuntime;
|
|
108
|
+
/** The resolved config. */
|
|
109
|
+
protected get config(): CoreConfig;
|
|
110
|
+
/** The agent's database (drizzle + migrations), built once per DO instance. */
|
|
111
|
+
protected get db(): AgentDB;
|
|
112
|
+
/**
|
|
113
|
+
* Which provider this agent's loops run on. Defaults to Workers AI; override
|
|
114
|
+
* to run on something else.
|
|
115
|
+
*
|
|
116
|
+
* The seam is here rather than in `models` because `models` memoizes, and a
|
|
117
|
+
* subclass overriding a memoized getter has to remember to keep the caching —
|
|
118
|
+
* a trap that only shows up as a performance bug. This is called once.
|
|
119
|
+
*
|
|
120
|
+
* `ModelRuntime` is the whole contract: return anything satisfying it and
|
|
121
|
+
* every loop in core keeps working unchanged. Core ships one implementation,
|
|
122
|
+
* {@link file://../agent/workers-ai/index.ts `agent/workers-ai`} (the default
|
|
123
|
+
* below); a second provider is one more
|
|
124
|
+
* {@link file://../agent/model.ts ModelRuntimeFactory}, defined here or in the
|
|
125
|
+
* consumer, not a change to anything on this path.
|
|
126
|
+
*
|
|
127
|
+
* Takes the resolved {@link ModelConfig} rather than reading `this.config`, so
|
|
128
|
+
* that this signature matches
|
|
129
|
+
* {@link file://../round/subagent.ts RecipeSubagentHost.modelRuntime} — an
|
|
130
|
+
* agent and its facet **must** run the same provider, and identical seams are
|
|
131
|
+
* what let one factory serve both instead of two hand-copied bodies.
|
|
132
|
+
*/
|
|
133
|
+
protected modelRuntime(model: ModelConfig): ModelRuntime;
|
|
134
|
+
/** The model runtime for this instance, built lazily and memoized. */
|
|
135
|
+
protected get models(): ModelRuntime;
|
|
136
|
+
/**
|
|
137
|
+
* What this agent's plugins are handed. Built from
|
|
138
|
+
* {@link resolvedModelIds} rather than `this.config`, which would be a cycle —
|
|
139
|
+
* building the runtime is what needs these.
|
|
140
|
+
*/
|
|
141
|
+
protected pluginHost(): PluginHost<TEnv>;
|
|
142
|
+
/**
|
|
143
|
+
* The model settings a locally-declared recipe runs on, resolved *before* the
|
|
144
|
+
* runtime exists.
|
|
145
|
+
*
|
|
146
|
+
* Deliberately not `this.config` — that would be a cycle. `resolveConfig` is
|
|
147
|
+
* cheap and pure and fills in core's baseline, so this is the same result the
|
|
148
|
+
* runtime lands on; that matters because every recipe runs on exactly this
|
|
149
|
+
* pair — `RecipePolicy` carries it and `validateRecipe` stamps it on.
|
|
150
|
+
*/
|
|
151
|
+
private resolvedModelIds;
|
|
152
|
+
onStart(): Promise<void>;
|
|
153
|
+
/**
|
|
154
|
+
* Cron handler: delete task rows older than 30 days. Runs Sunday 01:00 UTC.
|
|
155
|
+
*
|
|
156
|
+
* A plugin's own tables are its business — core's journal does not reach them,
|
|
157
|
+
* and neither does this sweep. A subclass with more durable state of its own
|
|
158
|
+
* overrides {@link cleanupAgentState}.
|
|
159
|
+
*/
|
|
160
|
+
cleanupOldTasks(_payload: Record<string, never>, _schedule: Schedule): Promise<void>;
|
|
161
|
+
/** Extra durable state to age out alongside the task rows. Default: none. */
|
|
162
|
+
protected cleanupAgentState(): void;
|
|
163
|
+
/**
|
|
164
|
+
* The main agent's primary/fallback pair. With `metadata` it builds a fresh
|
|
165
|
+
* pair carrying that AI Gateway correlation tag (so an AI Gateway log ties the call
|
|
166
|
+
* to its task and round); without it — the Session's own compaction model — it
|
|
167
|
+
* reuses a memoized default. A test `modelsOverride` always wins.
|
|
168
|
+
*/
|
|
169
|
+
protected modelPair(metadata?: AiGatewayMetadata): ModelPair;
|
|
170
|
+
/**
|
|
171
|
+
* The one continuous Session for this caller (rebuilt from `this.sql` after
|
|
172
|
+
* eviction). Memoized — `identity` is constant for the DO's life, since the DO
|
|
173
|
+
* is keyed 1:1 by `identity.key`.
|
|
174
|
+
*
|
|
175
|
+
* `onMessagesDisplaced` is the whole integration for anything that wants the
|
|
176
|
+
* messages a compaction folds away: core performs the compaction, so core
|
|
177
|
+
* announces the loss, and the runtime fans it out to every plugin that asked.
|
|
178
|
+
*/
|
|
179
|
+
getSession(identity: GatekeeperIdentity): SessionLike;
|
|
180
|
+
/**
|
|
181
|
+
* The caller key, which is present on every path that can reach a plugin.
|
|
182
|
+
*
|
|
183
|
+
* ## Why this does not just read the field
|
|
184
|
+
*
|
|
185
|
+
* `identityKey` is set on the first turn and lives in the isolate. An isolate
|
|
186
|
+
* does not live as long as the work does: it can be evicted between two rounds
|
|
187
|
+
* of the same task, and it can be reset outright — "Durable Object connection
|
|
188
|
+
* closed because the object was reset" — while a Workflow step is mid-flight.
|
|
189
|
+
* The next call arrives on a fresh instance where the field is empty, and
|
|
190
|
+
* every per-caller thunk built off it throws.
|
|
191
|
+
*
|
|
192
|
+
* That failure is disproportionate to its cause. A plugin asking which caller
|
|
193
|
+
* it is serving gets an exception, mid-task, on an object whose entire purpose
|
|
194
|
+
* is to be that caller's — and because the throw happens inside a tool or a
|
|
195
|
+
* runtime resolution rather than at the edge, it surfaces as a failed branch
|
|
196
|
+
* rather than as anything an operator can read.
|
|
197
|
+
*
|
|
198
|
+
* So the object answers from itself. `define-agent` routes with
|
|
199
|
+
* `ns.get(ns.idFromName(identity.key))`, which means the caller key *is* this
|
|
200
|
+
* object's name and the platform hands it back on `ctx.id.name` — durable, free
|
|
201
|
+
* and correct by construction: an object cannot disagree with the name it was
|
|
202
|
+
* addressed by.
|
|
203
|
+
*
|
|
204
|
+
* The field still wins when it is set. `id.name` is undefined for an object
|
|
205
|
+
* addressed by `newUniqueId()` or a raw id string, so it is a fallback rather
|
|
206
|
+
* than the source of truth, and the throw is kept for the case where neither
|
|
207
|
+
* exists.
|
|
208
|
+
*/
|
|
209
|
+
protected requireIdentityKey(): string;
|
|
210
|
+
/**
|
|
211
|
+
* Offer this deployment's own origin from a value that carries it. The first
|
|
212
|
+
* usable one is kept for the life of the instance.
|
|
213
|
+
*
|
|
214
|
+
* Called wherever a {@link TurnPushContext} arrives — here for every agent
|
|
215
|
+
* shape, and at the entry of `RoundAgentBase`'s two RPCs, where the origin is
|
|
216
|
+
* needed *before* this channel would be built. All three matter because any of
|
|
217
|
+
* them can be the call that wakes a fresh isolate. Cheap and unfailing: past
|
|
218
|
+
* the first turn it is one truthiness check, and an unusable value is ignored
|
|
219
|
+
* rather than thrown, because a turn must not fail over this.
|
|
220
|
+
*/
|
|
221
|
+
protected noteSelfOrigin(url: string | undefined): void;
|
|
222
|
+
/**
|
|
223
|
+
* This deployment's own public origin, if a turn has carried it to this
|
|
224
|
+
* instance yet. Constant once set, so it reads the same from any turn running
|
|
225
|
+
* on this object. See {@link SelfOrigin}.
|
|
226
|
+
*/
|
|
227
|
+
protected selfOrigin(): string | undefined;
|
|
228
|
+
/**
|
|
229
|
+
* The same, for a caller that cannot proceed without it — signing a caller
|
|
230
|
+
* token with {@link file://../a2a/caller-token.ts signCallerToken} above all,
|
|
231
|
+
* whose `iss` this is. Throws naming the timing rather than producing a token
|
|
232
|
+
* with a nonsense issuer.
|
|
233
|
+
*/
|
|
234
|
+
protected requireSelfOrigin(): string;
|
|
235
|
+
/** The gatekeeper callback channel for one turn. See {@link PushChannel}. */
|
|
236
|
+
protected push(context: TurnPushContext): PushChannel;
|
|
237
|
+
/**
|
|
238
|
+
* The per-request system-prompt suffix describing the verified caller.
|
|
239
|
+
*
|
|
240
|
+
* A rendering of a protocol fact rather than prompt copy, so core supplies one
|
|
241
|
+
* — see {@link callerContext}. Override it to name what a workspace id means in
|
|
242
|
+
* your deployment; do not use it to say who the *user* is, which this is not.
|
|
243
|
+
*/
|
|
244
|
+
protected callerContext(identity: GatekeeperIdentity): string;
|
|
245
|
+
beginTask(input: {
|
|
246
|
+
messageId: string;
|
|
247
|
+
taskId: string;
|
|
248
|
+
contextId: string;
|
|
249
|
+
}): Promise<PlainTask>;
|
|
250
|
+
getTask(taskId: string): Promise<PlainTask | null>;
|
|
251
|
+
listTasks(query: TaskListQuery): Promise<{
|
|
252
|
+
tasks: PlainTask[];
|
|
253
|
+
totalSize: number;
|
|
254
|
+
}>;
|
|
255
|
+
/**
|
|
256
|
+
* Persist a Task, returning **whether the guarded write applied**.
|
|
257
|
+
*
|
|
258
|
+
* That boolean is the cancellation check, and a caller must key its callback on
|
|
259
|
+
* it: `AgentDB` refuses to write a terminal state over a `canceled` row and
|
|
260
|
+
* does that read and write in one synchronous pass inside the DO. Probing with
|
|
261
|
+
* {@link getTask} first and saving second leaves a window — between the two
|
|
262
|
+
* calls, and again between the save and the notify — in which a cancel lands
|
|
263
|
+
* and the gatekeeper still receives a `completed` callback.
|
|
264
|
+
*
|
|
265
|
+
* A `canceled` state routes to {@link markCanceled} instead of a plain write,
|
|
266
|
+
* so a `tasks/cancel` arriving through the a2a-js TaskStore and one arriving
|
|
267
|
+
* through {@link cancelTask} converge on the same interruption path.
|
|
268
|
+
*/
|
|
269
|
+
saveTask(task: Task): Promise<boolean>;
|
|
270
|
+
/**
|
|
271
|
+
* Move the Task to `working`. Returns `"canceled"` when the caller cancelled
|
|
272
|
+
* first — read it and stop, rather than probing with a separate
|
|
273
|
+
* {@link getTask}, which reopens the gap between asking and acting.
|
|
274
|
+
*
|
|
275
|
+
* Anything else is `"ok"`, including an unknown row and a row already `working`
|
|
276
|
+
* (a replayed step): only an actual cancellation stops the pipeline.
|
|
277
|
+
*/
|
|
278
|
+
markWorking(taskId: string): Promise<"ok" | "canceled">;
|
|
279
|
+
cancelTask(taskId: string): Promise<PlainTask | null>;
|
|
280
|
+
/**
|
|
281
|
+
* The one place a Task becomes canceled: flip the row — terminal, so every
|
|
282
|
+
* non-canceled write is refused afterwards — then interrupt whatever is still
|
|
283
|
+
* running for it.
|
|
284
|
+
*
|
|
285
|
+
* `task` is supplied when the caller already built the canceled Task (the
|
|
286
|
+
* a2a-js cancel branch attaches its own status message); otherwise the row's
|
|
287
|
+
* own guarded flip produces it. Both paths are guarded against the same race:
|
|
288
|
+
* a task that already reached `completed`/`failed` refuses the write, and its
|
|
289
|
+
* verdict — not a `get` read straight after, which would return that
|
|
290
|
+
* unchanged terminal row and be mistaken for a successful cancellation — is
|
|
291
|
+
* what decides whether {@link onTaskCanceled} runs at all.
|
|
292
|
+
*/
|
|
293
|
+
private markCanceled;
|
|
294
|
+
/**
|
|
295
|
+
* Interrupt work still in flight for a task that has just been canceled.
|
|
296
|
+
*
|
|
297
|
+
* Default: nothing, which is right for an agent whose turn is a single
|
|
298
|
+
* inference — the row is terminal and the next guarded write refuses. An agent
|
|
299
|
+
* with children overrides this to abort them.
|
|
300
|
+
*
|
|
301
|
+
* **Must be best-effort.** Cancellation has already been recorded by the time
|
|
302
|
+
* this runs, and it must not fail because cleanup did.
|
|
303
|
+
*/
|
|
304
|
+
protected onTaskCanceled(_taskId: string): Promise<void>;
|
|
305
|
+
}
|