@spine-event-engine/server 2.0.0-snapshot.21 → 2.0.0-snapshot.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -7
- package/REFERENCE.md +199 -19
- package/dist/agent/agent-admission.d.ts +80 -0
- package/dist/agent/agent-admission.d.ts.map +1 -0
- package/dist/agent/agent-admission.js +127 -0
- package/dist/agent/agent-admission.js.map +1 -0
- package/dist/agent/agent-ai-binding.d.ts +24 -0
- package/dist/agent/agent-ai-binding.d.ts.map +1 -0
- package/dist/agent/agent-ai-binding.js +48 -0
- package/dist/agent/agent-ai-binding.js.map +1 -0
- package/dist/agent/agent-ai-runtime.d.ts +76 -0
- package/dist/agent/agent-ai-runtime.d.ts.map +1 -0
- package/dist/agent/agent-ai-runtime.js +1269 -0
- package/dist/agent/agent-ai-runtime.js.map +1 -0
- package/dist/agent/agent-execution-capacity.d.ts +43 -0
- package/dist/agent/agent-execution-capacity.d.ts.map +1 -0
- package/dist/agent/agent-execution-capacity.js +147 -0
- package/dist/agent/agent-execution-capacity.js.map +1 -0
- package/dist/agent/agent-execution-fault.d.ts +18 -0
- package/dist/agent/agent-execution-fault.d.ts.map +1 -0
- package/dist/agent/agent-execution-fault.js +31 -0
- package/dist/agent/agent-execution-fault.js.map +1 -0
- package/dist/agent/agent-execution-session.d.ts +103 -0
- package/dist/agent/agent-execution-session.d.ts.map +1 -0
- package/dist/agent/agent-execution-session.js +238 -0
- package/dist/agent/agent-execution-session.js.map +1 -0
- package/dist/agent/agent-history.d.ts +148 -0
- package/dist/agent/agent-history.d.ts.map +1 -0
- package/dist/agent/agent-history.js +340 -0
- package/dist/agent/agent-history.js.map +1 -0
- package/dist/agent/agent-interaction-audit.d.ts +58 -0
- package/dist/agent/agent-interaction-audit.d.ts.map +1 -0
- package/dist/agent/agent-interaction-audit.js +114 -0
- package/dist/agent/agent-interaction-audit.js.map +1 -0
- package/dist/agent/agent-interaction-events.d.ts +40 -0
- package/dist/agent/agent-interaction-events.d.ts.map +1 -0
- package/dist/agent/agent-interaction-events.js +129 -0
- package/dist/agent/agent-interaction-events.js.map +1 -0
- package/dist/agent/agent-mcp-budget.d.ts +125 -0
- package/dist/agent/agent-mcp-budget.d.ts.map +1 -0
- package/dist/agent/agent-mcp-budget.js +566 -0
- package/dist/agent/agent-mcp-budget.js.map +1 -0
- package/dist/agent/agent-mcp-host.d.ts +125 -0
- package/dist/agent/agent-mcp-host.d.ts.map +1 -0
- package/dist/agent/agent-mcp-host.js +15 -0
- package/dist/agent/agent-mcp-host.js.map +1 -0
- package/dist/agent/agent-mcp-runtime.d.ts +199 -0
- package/dist/agent/agent-mcp-runtime.d.ts.map +1 -0
- package/dist/agent/agent-mcp-runtime.js +621 -0
- package/dist/agent/agent-mcp-runtime.js.map +1 -0
- package/dist/agent/agent-model-selection.d.ts +129 -0
- package/dist/agent/agent-model-selection.d.ts.map +1 -0
- package/dist/agent/agent-model-selection.js +342 -0
- package/dist/agent/agent-model-selection.js.map +1 -0
- package/dist/agent/agent-read-runtime.d.ts +70 -0
- package/dist/agent/agent-read-runtime.d.ts.map +1 -0
- package/dist/agent/agent-read-runtime.js +320 -0
- package/dist/agent/agent-read-runtime.js.map +1 -0
- package/dist/agent/agent-revisions.d.ts +35 -0
- package/dist/agent/agent-revisions.d.ts.map +1 -0
- package/dist/agent/agent-revisions.js +133 -0
- package/dist/agent/agent-revisions.js.map +1 -0
- package/dist/agent/agent-scheduler.d.ts +99 -0
- package/dist/agent/agent-scheduler.d.ts.map +1 -0
- package/dist/agent/agent-scheduler.js +398 -0
- package/dist/agent/agent-scheduler.js.map +1 -0
- package/dist/bus/command-bus.d.ts +62 -0
- package/dist/bus/command-bus.d.ts.map +1 -1
- package/dist/bus/command-bus.js +51 -2
- package/dist/bus/command-bus.js.map +1 -1
- package/dist/bus/event-bus.d.ts +137 -3
- package/dist/bus/event-bus.d.ts.map +1 -1
- package/dist/bus/event-bus.js +133 -2
- package/dist/bus/event-bus.js.map +1 -1
- package/dist/bus/saved-dispatcher-binding.d.ts +96 -0
- package/dist/bus/saved-dispatcher-binding.d.ts.map +1 -0
- package/dist/bus/saved-dispatcher-binding.js +35 -0
- package/dist/bus/saved-dispatcher-binding.js.map +1 -0
- package/dist/context/bounded-context.d.ts +36 -2
- package/dist/context/bounded-context.d.ts.map +1 -1
- package/dist/context/bounded-context.js +253 -54
- package/dist/context/bounded-context.js.map +1 -1
- package/dist/context/entity-inbox.d.ts.map +1 -1
- package/dist/context/entity-inbox.js +5 -5
- package/dist/context/entity-inbox.js.map +1 -1
- package/dist/context/projection-handoff.d.ts.map +1 -1
- package/dist/context/projection-handoff.js +2 -1
- package/dist/context/projection-handoff.js.map +1 -1
- package/dist/context/tenant-index.d.ts +25 -0
- package/dist/context/tenant-index.d.ts.map +1 -1
- package/dist/context/tenant-index.js +45 -1
- package/dist/context/tenant-index.js.map +1 -1
- package/dist/delivery/delivery.d.ts.map +1 -1
- package/dist/delivery/delivery.js +4 -3
- package/dist/delivery/delivery.js.map +1 -1
- package/dist/delivery/inbox-records.d.ts +13 -0
- package/dist/delivery/inbox-records.d.ts.map +1 -1
- package/dist/delivery/inbox-records.js +204 -30
- package/dist/delivery/inbox-records.js.map +1 -1
- package/dist/delivery/inbox-storage.d.ts.map +1 -1
- package/dist/delivery/inbox-storage.js +26 -5
- package/dist/delivery/inbox-storage.js.map +1 -1
- package/dist/delivery/inbox.d.ts +7 -7
- package/dist/delivery/inbox.d.ts.map +1 -1
- package/dist/delivery/inbox.js +1 -2
- package/dist/delivery/inbox.js.map +1 -1
- package/dist/delivery/sharded-work-registry.d.ts +1 -0
- package/dist/delivery/sharded-work-registry.d.ts.map +1 -1
- package/dist/delivery/sharded-work-registry.js +3 -1
- package/dist/delivery/sharded-work-registry.js.map +1 -1
- package/dist/entity/entity-transaction.d.ts.map +1 -1
- package/dist/entity/entity-transaction.js +2 -6
- package/dist/entity/entity-transaction.js.map +1 -1
- package/dist/entity/entity.d.ts +82 -3
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +121 -22
- package/dist/entity/entity.js.map +1 -1
- package/dist/handler/generated-handler-registry.js +8 -3
- package/dist/handler/generated-handler-registry.js.map +1 -1
- package/dist/handler/handler-metadata.d.ts +17 -1
- package/dist/handler/handler-metadata.d.ts.map +1 -1
- package/dist/handler/handler-metadata.js +10 -4
- package/dist/handler/handler-metadata.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/integration/third-party-context.d.ts +5 -0
- package/dist/integration/third-party-context.d.ts.map +1 -1
- package/dist/integration/third-party-context.js +7 -6
- package/dist/integration/third-party-context.js.map +1 -1
- package/dist/repository/commit-fence.d.ts +11 -0
- package/dist/repository/commit-fence.d.ts.map +1 -1
- package/dist/repository/commit-fence.js +13 -0
- package/dist/repository/commit-fence.js.map +1 -1
- package/dist/repository/repository.d.ts +222 -13
- package/dist/repository/repository.d.ts.map +1 -1
- package/dist/repository/repository.js +2329 -137
- package/dist/repository/repository.js.map +1 -1
- package/dist/runtime/signal-metadata.d.ts +7 -47
- package/dist/runtime/signal-metadata.d.ts.map +1 -1
- package/dist/runtime/signal-metadata.js +8 -62
- package/dist/runtime/signal-metadata.js.map +1 -1
- package/dist/runtime/signal-publisher.d.ts +6 -0
- package/dist/runtime/signal-publisher.d.ts.map +1 -1
- package/dist/runtime/signal-publisher.js +13 -0
- package/dist/runtime/signal-publisher.js.map +1 -1
- package/dist/runtime/standalone-handler-runtime.d.ts +7 -0
- package/dist/runtime/standalone-handler-runtime.d.ts.map +1 -1
- package/dist/runtime/standalone-handler-runtime.js +148 -11
- package/dist/runtime/standalone-handler-runtime.js.map +1 -1
- package/dist/server/managed-server-application.d.ts +36 -6
- package/dist/server/managed-server-application.d.ts.map +1 -1
- package/dist/server/managed-server-application.js +257 -4
- package/dist/server/managed-server-application.js.map +1 -1
- package/dist/server/server.d.ts +9 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +13 -1
- package/dist/server/server.js.map +1 -1
- package/dist/stand/subscription-registry.d.ts.map +1 -1
- package/dist/stand/subscription-registry.js +9 -8
- package/dist/stand/subscription-registry.js.map +1 -1
- package/dist/testing/index.d.ts +57 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +87 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -12
package/README.md
CHANGED
|
@@ -82,10 +82,12 @@ for the exact contract.
|
|
|
82
82
|
|
|
83
83
|
An `@Assign`, `@Command`, `@React`, or `@Subscribe` handler may return its
|
|
84
84
|
usual result directly or through exactly one built-in `Promise<T>` layer. Its
|
|
85
|
-
|
|
85
|
+
in-memory Entity draft remains active until that promise settles. Nested `Promise<Promise<T>>`
|
|
86
86
|
results and structural or imported thenable lookalikes are rejected during handler
|
|
87
|
-
analysis.
|
|
88
|
-
|
|
87
|
+
analysis. Storage writes happen in separate short operations after the handler succeeds.
|
|
88
|
+
A failed handler leaves previous persisted state unchanged and
|
|
89
|
+
suppresses produced output. An external HTTP request or other side effect may
|
|
90
|
+
already have happened.
|
|
89
91
|
|
|
90
92
|
Handler return declarations can use native unions for one of several results,
|
|
91
93
|
or fixed tuples for several ordered results. For example,
|
|
@@ -129,7 +131,11 @@ class TaskAssignee {
|
|
|
129
131
|
Place the primary handler decorator first for readability. Reversing the two
|
|
130
132
|
decorators has the same behavior.
|
|
131
133
|
|
|
132
|
-
Process Managers
|
|
134
|
+
Process Managers have protected read-only `select()` during a handler. Agents use
|
|
135
|
+
the generated `select(query).read()` form with the same actor, tenant, and
|
|
136
|
+
1,000-state limits. Aggregates do not expose handler-scoped queries.
|
|
137
|
+
|
|
138
|
+
For Process Manager's schema-and-columns query form:
|
|
133
139
|
|
|
134
140
|
```ts
|
|
135
141
|
import { EntityQuery, type EntityColumn } from "@spine-event-engine/core";
|
|
@@ -167,11 +173,11 @@ These reads are eventually consistent. `limit()` may not exceed 1,000, and
|
|
|
167
173
|
`all()` can be expensive for a large read model; prefer a targeted, ordered,
|
|
168
174
|
bounded query.
|
|
169
175
|
|
|
170
|
-
The Entity type identifies its
|
|
176
|
+
The Entity type identifies its Bounded Context among those registered with the same
|
|
171
177
|
`Server`. For example, an order process can query a product in a catalogue
|
|
172
|
-
|
|
178
|
+
Bounded Context without naming that Bounded Context. An Entity in another Bounded Context must allow
|
|
173
179
|
queries (`query` or `full` visibility). Registering the same Entity type in two
|
|
174
|
-
|
|
180
|
+
Bounded Contexts causes a startup error.
|
|
175
181
|
|
|
176
182
|
The [Orders example](https://github.com/SpineEventEngine/spine-ts/blob/master/examples/orders/README.md#cross-context-order-review)
|
|
177
183
|
shows this in an Event handler and includes a runnable integration test.
|
|
@@ -185,6 +191,97 @@ for the complete tenant rules and empty-result behavior.
|
|
|
185
191
|
Use `EntityQuery.all(...)` when every predicate must match and
|
|
186
192
|
`EntityQuery.either(...)` when any branch may match.
|
|
187
193
|
|
|
194
|
+
## Draft with an Agent
|
|
195
|
+
|
|
196
|
+
An Agent is a stateful Entity that can ask a model for help while handling a
|
|
197
|
+
Command or Event. For example, a support Agent drafts a reply from ticket facts
|
|
198
|
+
and emits an Event for a person to review. It keeps provider credentials out of
|
|
199
|
+
the handler and records the model interaction. Like other Entities, its ID and
|
|
200
|
+
state are declared in Proto and its handlers use generated registration.
|
|
201
|
+
|
|
202
|
+
An Agent can read its recorded interactions and emitted domain Events through
|
|
203
|
+
its repository. See the [Agent execution reference](REFERENCE.md#agent-execution)
|
|
204
|
+
for history methods, paging, and recovery behavior.
|
|
205
|
+
|
|
206
|
+
Declare the Agent ID and state in Proto, with `option (entity).kind = ENTITY;`
|
|
207
|
+
on the state. The [Support example](https://github.com/SpineEventEngine/spine-ts/blob/master/examples/support/README.md) includes
|
|
208
|
+
complete [domain Protos](https://github.com/SpineEventEngine/spine-ts/blob/master/examples/support/proto/spine/examples/support/states.proto),
|
|
209
|
+
[a model definition](https://github.com/SpineEventEngine/spine-ts/blob/master/examples/support/src/model.ts), and
|
|
210
|
+
[an Agent implementation](https://github.com/SpineEventEngine/spine-ts/blob/master/examples/support/src/index.ts).
|
|
211
|
+
|
|
212
|
+
The handler invokes a typed model operation, updates its draft only on success,
|
|
213
|
+
and emits a domain outcome. This abbreviated declaration uses the example's
|
|
214
|
+
actual generated messages:
|
|
215
|
+
|
|
216
|
+
<!-- prettier-ignore-start -->
|
|
217
|
+
|
|
218
|
+
<!-- docs-snippet-path: examples/support/src/index.ts -->
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
import { create } from "@bufbuild/protobuf";
|
|
222
|
+
import { Agent, Assign } from "@spine-event-engine/server";
|
|
223
|
+
import type { DraftSupportReply } from "../generated/spine/examples/support/commands_pb.js";
|
|
224
|
+
import {
|
|
225
|
+
SupportReplySuggestedSchema,
|
|
226
|
+
SupportReplyFailedSchema,
|
|
227
|
+
type SupportReplySuggested,
|
|
228
|
+
type SupportReplyFailed,
|
|
229
|
+
} from "../generated/spine/examples/support/events_pb.js";
|
|
230
|
+
import { SupportDraftStateSchema } from "../generated/spine/examples/support/states_pb.js";
|
|
231
|
+
import type { SupportTicketId } from "../generated/spine/examples/support/types_pb.js";
|
|
232
|
+
import { draftSupportReply } from "./model.js";
|
|
233
|
+
|
|
234
|
+
/** Proposes support replies for a person's review. */
|
|
235
|
+
class SupportDraftAgent extends Agent<SupportTicketId, typeof SupportDraftStateSchema> {
|
|
236
|
+
/**
|
|
237
|
+
* Drafts a reply from the submitted ticket facts.
|
|
238
|
+
*
|
|
239
|
+
* @param command Ticket facts and an explicit conversation.
|
|
240
|
+
* @returns The proposed reply or a recorded failure outcome.
|
|
241
|
+
*/
|
|
242
|
+
@Assign
|
|
243
|
+
async draft(command: DraftSupportReply): Promise<SupportReplySuggested | SupportReplyFailed> {
|
|
244
|
+
if (command.conversation === undefined || command.request === undefined)
|
|
245
|
+
throw new TypeError("A draft requires ticket facts and a conversation.");
|
|
246
|
+
const result = await this.ai.invoke(draftSupportReply, {
|
|
247
|
+
call: "draft-support-reply",
|
|
248
|
+
conversation: command.conversation,
|
|
249
|
+
input: command,
|
|
250
|
+
});
|
|
251
|
+
const outcome = {
|
|
252
|
+
id: this.id,
|
|
253
|
+
request: command.request,
|
|
254
|
+
conversation: command.conversation,
|
|
255
|
+
operation: result.operationId,
|
|
256
|
+
};
|
|
257
|
+
if (!result.ok) return create(SupportReplyFailedSchema, outcome);
|
|
258
|
+
this.update((state) =>
|
|
259
|
+
Object.assign(state, {
|
|
260
|
+
id: this.id,
|
|
261
|
+
request: command.request,
|
|
262
|
+
conversation: command.conversation,
|
|
263
|
+
reply: result.value,
|
|
264
|
+
}),
|
|
265
|
+
);
|
|
266
|
+
return create(SupportReplySuggestedSchema, { ...outcome, reply: result.value });
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
<!-- prettier-ignore-end -->
|
|
272
|
+
|
|
273
|
+
Configure the registry outside the Entity. The Bounded Context requires persisted System
|
|
274
|
+
Events, and the Agent registration supplies its code revision and permitted
|
|
275
|
+
capabilities. The [example Bounded Context factory](https://github.com/SpineEventEngine/spine-ts/blob/master/examples/support/src/index.ts)
|
|
276
|
+
assembles these settings with the generated handler registry. A server-wide
|
|
277
|
+
`withAi()` default can be supplied when building Bounded Contexts through `Server`;
|
|
278
|
+
Bounded Context configuration can provide its registry directly.
|
|
279
|
+
|
|
280
|
+
Posting a Command awaits acceptance. Model work and the resulting domain Event
|
|
281
|
+
arrive asynchronously afterward. The handling operation can await a model without
|
|
282
|
+
keeping a database transaction open. See the [Agent execution reference](REFERENCE.md#agent-execution)
|
|
283
|
+
for defaults, recovery and retained history.
|
|
284
|
+
|
|
188
285
|
## Native lifecycle and routing
|
|
189
286
|
|
|
190
287
|
`Server.run()` is the standalone process form: it handles `SIGINT`/`SIGTERM`
|
package/REFERENCE.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# @spine-event-engine/server reference
|
|
2
2
|
|
|
3
|
-
This reference gives
|
|
4
|
-
server contracts. For an introduction and examples, start with the
|
|
3
|
+
This reference gives coding agents the detailed server contracts. For an introduction and examples, start with the
|
|
5
4
|
[server README](README.md).
|
|
6
5
|
|
|
7
6
|
## Testing entry point
|
|
@@ -238,11 +237,13 @@ route registration API.
|
|
|
238
237
|
|
|
239
238
|
Handlers may return their established result directly or through exactly one built-in `Promise<T>`.
|
|
240
239
|
Nested promises and structural or imported thenable lookalikes are rejected during handler analysis.
|
|
241
|
-
The
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
240
|
+
The in-memory Entity draft remains active until that promise settles. Storage
|
|
241
|
+
writes use separate short operations after the handler succeeds; a rejected
|
|
242
|
+
handler leaves no partial persisted state or produced signals, but cannot undo
|
|
243
|
+
external side effects. Process Managers may use their protected read-only query
|
|
244
|
+
surface for eventually consistent Entity state during a handler. Agents expose
|
|
245
|
+
the generated `select(query).read()` form under the same handler scope and
|
|
246
|
+
limits. Aggregates must not use these reads for invariants.
|
|
246
247
|
|
|
247
248
|
`select(schema, columns)` supports `byId`, typed `where`, `orderBy`,
|
|
248
249
|
`limit`, `read`, `findById`, and `all`. A Process Manager query returns at most
|
|
@@ -329,10 +330,11 @@ A command-input `@Command` method is a command substitution receptor: it is
|
|
|
329
330
|
the one effective receptor for that Command type (instead of an `@Assign`),
|
|
330
331
|
commits its Entity state before its one-or-more returned Commands are detached
|
|
331
332
|
for in-process produced-command enqueue, and receives an optional `CommandContext`.
|
|
332
|
-
|
|
333
|
-
Projection repositories reject command-input substitutions and event- or
|
|
333
|
+
Process Manager and Agent repositories support `@Command` handlers. Aggregate
|
|
334
|
+
and Projection repositories reject command-input substitutions and event- or
|
|
334
335
|
rejection-input command reactions during generated metadata ingestion and
|
|
335
|
-
repository construction.
|
|
336
|
+
repository construction. Agents reject `@Subscribe`, including Entity-state
|
|
337
|
+
Apply handlers, at generation and runtime registration.
|
|
336
338
|
Event- and rejection-input `@Command` methods remain Event- or
|
|
337
339
|
rejection-to-command reactions on Event Bus.
|
|
338
340
|
|
|
@@ -542,6 +544,11 @@ handler registry for classes registered with `add(EntityClass)`;
|
|
|
542
544
|
`buildAsync()` performs that discovery and assembly. `build()` remains for
|
|
543
545
|
explicit `Repository` registration. A built context contains `CommandBus`,
|
|
544
546
|
`EventBus`, `Stand`, repositories, and its storage lifecycle.
|
|
547
|
+
Trusted server-side code can call `context.getRepository(EntityClass)` to obtain
|
|
548
|
+
the already registered repository for that exact constructor. The lookup does
|
|
549
|
+
not create a repository or read Entity state; an absent class or closing
|
|
550
|
+
Bounded Context fails explicitly. Application code must authorize users before
|
|
551
|
+
exposing repository reads through a client bridge.
|
|
545
552
|
|
|
546
553
|
Generated writer output is an unversioned receiver collection and records
|
|
547
554
|
command substitutions explicitly. The ingestor rejects retired versioned
|
|
@@ -615,8 +622,10 @@ configuration and Datastore custom record storage registered for
|
|
|
615
622
|
`SubscriptionRecord` are used by the registry. The registry uses one
|
|
616
623
|
record-storage handle, while the context closes the registry.
|
|
617
624
|
|
|
618
|
-
`Entity` is the state base class. `Aggregate`, `Projection`,
|
|
619
|
-
`ProcessManager` identify the
|
|
625
|
+
`Entity` is the state base class. `Aggregate`, `Projection`,
|
|
626
|
+
`ProcessManager`, and `Agent` identify the four entity families. Agent state
|
|
627
|
+
declares canonical Proto kind `ENTITY` and uses the same Spine `Version`.
|
|
628
|
+
Handler decorators are
|
|
620
629
|
`@Assign`, `@Command`, `@React`, and `@Subscribe`. A command-accepting
|
|
621
630
|
handler uses `@Throws(GeneratedRejection)` to declare its possible domain
|
|
622
631
|
rejections. Write the primary handler decorator first and `@Throws` immediately
|
|
@@ -633,6 +642,172 @@ zero. A dispatch that produces Events or changes state or lifecycle advances it
|
|
|
633
642
|
once; no-op and rejected dispatches do not. Repositories restore and persist the
|
|
634
643
|
full Version, including its timestamp, across current state, history, and Stand.
|
|
635
644
|
|
|
645
|
+
## Agent execution
|
|
646
|
+
|
|
647
|
+
Agents extend `Agent<Id, typeof StateSchema>`. The state declares Proto kind
|
|
648
|
+
`ENTITY`; IDs, state, Version, validation and routing use the normal Entity
|
|
649
|
+
contracts. Agents accept `@Assign`, `@React` and `@Command`, including declared
|
|
650
|
+
rejections as inputs. They reject `@Subscribe` and Entity-state Apply handlers.
|
|
651
|
+
The Agent runs only after an accepted signal. A model response or timer cannot
|
|
652
|
+
start a new autonomous Entity loop.
|
|
653
|
+
|
|
654
|
+
### Configuration
|
|
655
|
+
|
|
656
|
+
Register a factory-created `AiRegistry`, enable `persistSystemEvents()`, and
|
|
657
|
+
configure `agentCodeRevision` plus `ai.models` for each Agent repository. Use
|
|
658
|
+
an empty `models` array when that Agent has no model calls. Readiness requires
|
|
659
|
+
indexed Agent history and execution storage from the selected provider.
|
|
660
|
+
The [Support Bounded Context](../../examples/support/src/index.ts) uses generated
|
|
661
|
+
registration with these options.
|
|
662
|
+
|
|
663
|
+
Configuration has these scopes:
|
|
664
|
+
|
|
665
|
+
| Scope | Setting | Effect |
|
|
666
|
+
| --------------- | ---------------------------------------- | ------------------------------------------------------------------------ |
|
|
667
|
+
| Server | `Server.withAi(registry)` | Default registry for Bounded Context builders assembled by that server. |
|
|
668
|
+
| Bounded Context | `BoundedContextBuilder.withAi(registry)` | Explicit registry replacing the server default for that Bounded Context. |
|
|
669
|
+
| Repository | `ai.defaultModels` | Generation and decision defaults before the registry's defaults. |
|
|
670
|
+
| Repository | `ai.allowedModels` | Deployment references the Agent may use. |
|
|
671
|
+
| Repository | `ai.resolveModel` | Optional accepted-source choice before the Agent handler. |
|
|
672
|
+
| Repository | `ai.authorizeSelection` | Authorizes explicit choices and staged preference changes. |
|
|
673
|
+
| Repository | `ai.invocationLimits` | Limits that can narrow the registry's whole-signal limits. |
|
|
674
|
+
| Instance | `this.ai.select(kind, ref)` | A saved preference applied to later accepted signals. |
|
|
675
|
+
|
|
676
|
+
A prebuilt Bounded Context already has its registry; adding it to a server does not
|
|
677
|
+
reconfigure it. An instance preference takes precedence over its repository
|
|
678
|
+
default, which takes precedence over the effective registry default. Passing
|
|
679
|
+
`undefined` to `select` restores inheritance. Selection must satisfy the
|
|
680
|
+
repository policy and `authorizeSelection` callback; it cannot extend the
|
|
681
|
+
repository's allowed deployments. The current signal keeps its original selection.
|
|
682
|
+
|
|
683
|
+
`resolveModel(kind, scope, sourceMessage, control)` can choose a registered
|
|
684
|
+
deployment from a detached copy of the original accepted Command or Event
|
|
685
|
+
payload. A concrete result overrides preference and default precedence for that
|
|
686
|
+
signal; `undefined` preserves it. This allows an Agent without a configured
|
|
687
|
+
default to start after a deployment is appended to the bound registry. The
|
|
688
|
+
runtime checks repository allowlists, capabilities and `authorizeSelection`
|
|
689
|
+
before saving the selection and connection identity. A saved selection is reused
|
|
690
|
+
on continuation. Resolver and authorization callbacks receive linked cancellation
|
|
691
|
+
and the smaller of the invocation deadline and registry hook timeout. An
|
|
692
|
+
effective `this.ai.select()` change, including reset to inheritance, is
|
|
693
|
+
authorized before the Entity transition and preference Events commit; a no-op
|
|
694
|
+
change skips that callback.
|
|
695
|
+
|
|
696
|
+
Model registrations resolve a credential-free connection identity and authorize
|
|
697
|
+
use for the original actor, tenant, Agent and source signal. Connection callbacks
|
|
698
|
+
can obtain an API key, refreshed token, cloud credential or local model handle
|
|
699
|
+
through application code. The optional adapter supplies a guarded fetch function
|
|
700
|
+
for provider construction. Spine does not implement a provider's login flow.
|
|
701
|
+
See [adapter configuration](../ai-vercel-ax/README.md).
|
|
702
|
+
|
|
703
|
+
### Acceptance and completion
|
|
704
|
+
|
|
705
|
+
Before acknowledging Agent intake, the runtime saves the original signal,
|
|
706
|
+
recipient, selected handlers and code/schema/policy revisions. The scheduler
|
|
707
|
+
processes one accepted signal at a time per Agent instance, under a provider
|
|
708
|
+
claim. Different instances can run concurrently within configured limits.
|
|
709
|
+
Bounded Contexts using the same registry object share its capacity within the process.
|
|
710
|
+
Signals beyond the bounded in-memory waiting queue remain durably pending.
|
|
711
|
+
Waiting before a fresh execution starts precedes its deadline. Once execution
|
|
712
|
+
starts, recovery continues with the saved deadline and counts. The same deadline
|
|
713
|
+
bounds an awaited application handler. Expiry or Bounded Context shutdown ends that wait
|
|
714
|
+
and prevents late handler results from changing Entity state or emitting signals;
|
|
715
|
+
it cannot stop arbitrary application JavaScript or undo external effects.
|
|
716
|
+
|
|
717
|
+
Newly accepted work supplies its repository and tenant to prompt discovery.
|
|
718
|
+
Periodic discovery reads tenant pages and constructs repository scopes as they
|
|
719
|
+
are needed. It retains at most one page of 16 tenants, four periodic scan scopes,
|
|
720
|
+
and 64 scopes awaiting a prompt scan. A turn requests at most one tenant page
|
|
721
|
+
and reads at most four pending-work pages. It does not load the complete tenant
|
|
722
|
+
catalog or retain a scan position for every tenant.
|
|
723
|
+
|
|
724
|
+
A sweep finishes before another begins. The next starts no earlier than five
|
|
725
|
+
seconds after the preceding sweep started, measured by `Time`; longer sweeps
|
|
726
|
+
restart after completion. This lets discovery reach tenants near the end of a
|
|
727
|
+
large catalog and find later admissions on the next sweep. Periodic scans keep
|
|
728
|
+
their turn during new arrivals, including while execution capacity is full.
|
|
729
|
+
A pending catalog request does not block prompt scans of known scopes.
|
|
730
|
+
|
|
731
|
+
Bounded Context shutdown stops waiting for discovery reads even if a provider ignores
|
|
732
|
+
cancellation. Late results cannot submit work or restart scanning. Built-in
|
|
733
|
+
adapters use their available cancellation and timeout controls; detaching the
|
|
734
|
+
scheduler does not guarantee cancellation of an already issued native request.
|
|
735
|
+
|
|
736
|
+
The signal's matching handlers share one Entity draft. Each handler can await
|
|
737
|
+
`this.ai.invoke()` through the protected Spine facade. Calls in one handler must
|
|
738
|
+
be sequential and finish before it returns. Requests, results and
|
|
739
|
+
validation failures are saved as the operation progresses. The final accepted
|
|
740
|
+
state, Version, history and original outgoing envelopes are committed under the
|
|
741
|
+
same execution claim. A no-op still completes its execution record. Waiting for
|
|
742
|
+
a provider does not hold a database transaction open.
|
|
743
|
+
|
|
744
|
+
Recovery compares the registered handler, schema and policy with accepted work.
|
|
745
|
+
A saved named call can reuse its result; changing that call's input or prepared
|
|
746
|
+
request is a mismatch, not a new attempt. Domain code should derive its decisions
|
|
747
|
+
from accepted signals and recorded reads. Arbitrary external effects performed
|
|
748
|
+
by handler code are outside the model/tool journal.
|
|
749
|
+
|
|
750
|
+
After completion, delivery uses the saved outgoing envelopes and recipient
|
|
751
|
+
bindings. The producing handler and model are not rerun to deliver them.
|
|
752
|
+
Downstream delivery is at least once: a recipient or standalone callback may be
|
|
753
|
+
called again with the same envelope. Application effects must account for that.
|
|
754
|
+
Generated repository and standalone receivers have the required binding metadata.
|
|
755
|
+
Matching raw custom dispatchers without that metadata are rejected for Agent
|
|
756
|
+
output; unrelated dispatchers and ordinary non-Agent posting keep their usual
|
|
757
|
+
behavior.
|
|
758
|
+
|
|
759
|
+
### Retained history
|
|
760
|
+
|
|
761
|
+
Every Agent records conversations, System Events and its emitted domain Events.
|
|
762
|
+
The paired System Context EventStore also keeps System Events. Agent history
|
|
763
|
+
reads use dedicated repository indexes for that instance and tenant, rather than
|
|
764
|
+
scanning the Bounded Context-wide stores. Memory storage lasts for the process; choose a
|
|
765
|
+
persistent provider when records must survive process termination.
|
|
766
|
+
|
|
767
|
+
| Protected method | Returned `HistoryPage.items` |
|
|
768
|
+
| ------------------------------ | ------------------------------------------------------------------------------ |
|
|
769
|
+
| `fullHistory(request)` | `AgentHistoryEntry` oneof: conversation record, System Event, or domain Event. |
|
|
770
|
+
| `conversationHistory(request)` | `ConversationRecord` for the required `conversation` ID. |
|
|
771
|
+
| `systemEventHistory(request)` | Original System Event envelopes. |
|
|
772
|
+
| `domainEventHistory(request)` | Original domain Event envelopes emitted by this Agent. |
|
|
773
|
+
|
|
774
|
+
All methods return newest entries first. A request supplies positive `pageSize`
|
|
775
|
+
and an optional opaque cursor; `nextCursor` continues toward older entries.
|
|
776
|
+
There is no fixed 100-item or page-byte ceiling. Reads made during a handler count
|
|
777
|
+
toward any configured invocation limits for recorded reads and recovery data. Ordering
|
|
778
|
+
uses the full Spine `Time` timestamp, category and existing record ID. There is
|
|
779
|
+
no repository-managed history counter. Cursors cannot be transferred across
|
|
780
|
+
Agents, tenants, categories or conversations.
|
|
781
|
+
|
|
782
|
+
Recording has no off switch, expiry policy or Agent-specific purge operation.
|
|
783
|
+
Archive and logical deletion retain the history. General physical Entity deletion
|
|
784
|
+
is a separate feature; this API does not introduce it. Authentication callbacks do not become conversation records. Hidden model
|
|
785
|
+
reasoning is not part of the audit API. The records describe the supplied
|
|
786
|
+
requests, received supported content, tool calls and admitted outcomes.
|
|
787
|
+
|
|
788
|
+
Use `BlackBox.readAgentHistory(AgentClass, id, request)` to inspect full
|
|
789
|
+
history in an application test. `BlackBox.readSystemEvents(ids)` reads the paired
|
|
790
|
+
System store by exact Event IDs. See the [testing reference](../testing/REFERENCE.md)
|
|
791
|
+
and [complete support tests](../../examples/support/test/support-blackbox.test.ts).
|
|
792
|
+
|
|
793
|
+
For a trusted application bridge, `context.getRepository(AgentClass)` returns
|
|
794
|
+
the registered Agent `Repository`, which exposes
|
|
795
|
+
`agentHistory(id, scope)` with the same four history methods and page contracts.
|
|
796
|
+
The scope is explicit: pass `{}` in a single-tenant Bounded Context or
|
|
797
|
+
`{ tenantId }` in a multitenant Bounded Context. The repository also exposes
|
|
798
|
+
`agentExecution(id, sourceCommandOrEventId, scope)` for the exact recorded phase:
|
|
799
|
+
`accepted`, `active`, `completed-pending-delivery`, `completed`, or `terminated`.
|
|
800
|
+
An absent record returns `undefined`; it does not establish completion. These
|
|
801
|
+
reads use indexed storage without restoring an Agent. The application bridge
|
|
802
|
+
must authorize access before calling either method; actor metadata does not
|
|
803
|
+
grant read permission.
|
|
804
|
+
|
|
805
|
+
If a selected model's `authorizeUse` callback explicitly returns `false` at
|
|
806
|
+
Agent claim time, the execution becomes `terminated` with one
|
|
807
|
+
`AgentInvocationTerminated` System Event carrying `MODEL_USE_DENIED`. No Agent
|
|
808
|
+
handler runs and no application-domain result Event is emitted. Callback
|
|
809
|
+
exceptions and infrastructure failures remain distinct from this denial.
|
|
810
|
+
|
|
636
811
|
## Signals, validation, and rejection behavior
|
|
637
812
|
|
|
638
813
|
`CommandBus` validates every accepted command from Proto validation options
|
|
@@ -646,18 +821,18 @@ UUIDs; fixed IDs belong only to existing source envelopes retained through the
|
|
|
646
821
|
normal origin chain.
|
|
647
822
|
|
|
648
823
|
An application handler throws a generated core `RejectionThrowable` for a
|
|
649
|
-
domain rejection declared with `@Throws`. The repository
|
|
650
|
-
|
|
824
|
+
domain rejection declared with `@Throws`. The repository discards the unaccepted
|
|
825
|
+
draft and output, retaining the previous state, Version and lifecycle; it schedules the typed rejection event independently. Command service
|
|
651
826
|
acknowledgement remains an accepted `Ack`. Rejection-event posting can be
|
|
652
827
|
unobserved by inactive, full, or closed subscriptions and a posting failure is
|
|
653
828
|
an internal diagnostic, not a retry guarantee.
|
|
654
829
|
|
|
655
830
|
Every domain context has an internal paired System Context. Domain events use
|
|
656
831
|
the domain `EventBus` and domain `EventStore`. System events use only the
|
|
657
|
-
System Context `EventBus`, so they never enter the domain EventStore.
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
and notifies without appending. Schemas may come from an external dispatcher or
|
|
832
|
+
System Context `EventBus`, so they never enter the domain EventStore.
|
|
833
|
+
`persistSystemEvents()` enables the paired System Context's separate storage.
|
|
834
|
+
Bounded Contexts with Agents must enable it. For other Bounded Contexts it is optional; without
|
|
835
|
+
it, the bus validates, dispatches and notifies without appending. Schemas may come from an external dispatcher or
|
|
661
836
|
a registered internal repository producer. A producer-only schema is not
|
|
662
837
|
thereby an external dispatch route.
|
|
663
838
|
|
|
@@ -822,6 +997,11 @@ updates, and process-manager reactions. Callbacks are at-least-once/replay-safe:
|
|
|
822
997
|
lost renewal can prevent stale finalization but cannot undo a callback already
|
|
823
998
|
run. The package exposes no general raw worker callback API.
|
|
824
999
|
|
|
1000
|
+
Inbox reads return `InboxMessage` with a full-precision Protobuf `Timestamp` in
|
|
1001
|
+
`whenReceived`. `InboxMessageInput` requires a precise `Timestamp` for new
|
|
1002
|
+
receipts. Writes, acknowledgements, and exact removals use an `InboxMessage`
|
|
1003
|
+
with the same Timestamp contract.
|
|
1004
|
+
|
|
825
1005
|
Shard ownership is the only delivery exclusion mechanism and excludes
|
|
826
1006
|
concurrent delivery within that shard. Pending and delivered `InboxMessage`
|
|
827
1007
|
rows are direct records; a delivered row is the deduplication fact. A handler
|
|
@@ -858,7 +1038,7 @@ const context = BoundedContext.singleTenant("Tasks")
|
|
|
858
1038
|
.build();
|
|
859
1039
|
```
|
|
860
1040
|
|
|
861
|
-
Aggregate commands and Process Manager commands/events derive their target shard
|
|
1041
|
+
Aggregate commands and Process Manager or Agent commands/events derive their target shard
|
|
862
1042
|
internally and persist their envelope in the target Entity Inbox before any
|
|
863
1043
|
handler runs. Local intake can directly drain the persisted Inbox in the
|
|
864
1044
|
current request path. Attached `ServerEnvironment` ports acknowledge admission
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Any } from "@bufbuild/protobuf/wkt";
|
|
2
|
+
import type { ActorContext, Command, Event } from "@spine-event-engine/proto";
|
|
3
|
+
import { type AgentAcceptedInvocation, type AgentHandlerBinding } from "@spine-event-engine/proto/generated/spine/server/agent/execution_record_pb.js";
|
|
4
|
+
import type { RegisteredHandlerMetadata } from "../handler/handler-metadata.js";
|
|
5
|
+
import type { InboxMessage } from "../delivery/inbox.js";
|
|
6
|
+
/**
|
|
7
|
+
* Complete source and selected bindings at one durable Inbox handoff.
|
|
8
|
+
*/
|
|
9
|
+
export interface AgentAdmissionInput {
|
|
10
|
+
/**
|
|
11
|
+
* Generated Agent state type.
|
|
12
|
+
*/
|
|
13
|
+
readonly stateType: string;
|
|
14
|
+
/**
|
|
15
|
+
* Canonical storage key of the typed recipient.
|
|
16
|
+
*/
|
|
17
|
+
readonly agentKey: string;
|
|
18
|
+
/**
|
|
19
|
+
* Original typed recipient from the persisted Inbox row.
|
|
20
|
+
*/
|
|
21
|
+
readonly recipientId: Any;
|
|
22
|
+
/**
|
|
23
|
+
* Original Command or Event envelope.
|
|
24
|
+
*/
|
|
25
|
+
readonly signal: {
|
|
26
|
+
readonly kind: "command";
|
|
27
|
+
readonly value: Command;
|
|
28
|
+
} | {
|
|
29
|
+
readonly kind: "event";
|
|
30
|
+
readonly value: Event;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Actor selected from the original envelope.
|
|
34
|
+
*/
|
|
35
|
+
readonly actor: ActorContext;
|
|
36
|
+
/**
|
|
37
|
+
* Original durable Inbox receipt and order.
|
|
38
|
+
*/
|
|
39
|
+
readonly inbox: InboxMessage;
|
|
40
|
+
/**
|
|
41
|
+
* Every matching handler in actual execution order.
|
|
42
|
+
*/
|
|
43
|
+
readonly handlers: readonly RegisteredHandlerMetadata[];
|
|
44
|
+
/**
|
|
45
|
+
* Application build revision supplied by Agent registration.
|
|
46
|
+
*/
|
|
47
|
+
readonly codeRevision: string;
|
|
48
|
+
/**
|
|
49
|
+
* Descriptor digest of accepted generated schemas.
|
|
50
|
+
*/
|
|
51
|
+
readonly schemaRevision: string;
|
|
52
|
+
/**
|
|
53
|
+
* Digest of effective AI policy and configuration.
|
|
54
|
+
*/
|
|
55
|
+
readonly policyRevision: string;
|
|
56
|
+
}
|
|
57
|
+
interface AgentAdmissionAccess {
|
|
58
|
+
/**
|
|
59
|
+
* Copies the exact accepted recipient and selected bindings for durable admission.
|
|
60
|
+
*
|
|
61
|
+
* @param input Routed Inbox work and registration revisions.
|
|
62
|
+
* @returns Immutable accepted invocation content.
|
|
63
|
+
*/
|
|
64
|
+
create(input: AgentAdmissionInput): AgentAcceptedInvocation;
|
|
65
|
+
/**
|
|
66
|
+
* Compares every persisted handler-binding field with current registration.
|
|
67
|
+
*
|
|
68
|
+
* @param accepted Binding saved with the original invocation.
|
|
69
|
+
* @param registered Current generated handler metadata.
|
|
70
|
+
* @param ordinal Expected position in the accepted handler order.
|
|
71
|
+
* @returns Whether current registration exactly matches the saved binding.
|
|
72
|
+
*/
|
|
73
|
+
matchesHandler(accepted: AgentHandlerBinding, registered: RegisteredHandlerMetadata, ordinal: number): boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Materializes provider admission without running application handlers.
|
|
77
|
+
*/
|
|
78
|
+
export declare const AgentAdmission: AgentAdmissionAccess;
|
|
79
|
+
export {};
|
|
80
|
+
//# sourceMappingURL=agent-admission.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-admission.d.ts","sourceRoot":"","sources":["../../src/agent/agent-admission.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAYL,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EAEzB,MAAM,+EAA+E,CAAC;AACvF,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAChF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,MAAM,EACX;QAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GACrD;QAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC;IAEtD;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAE7B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAE7B;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAExD;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAE9B;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAEhC;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,UAAU,oBAAoB;IAC5B;;;;;OAKG;IACH,MAAM,CAAC,KAAK,EAAE,mBAAmB,GAAG,uBAAuB,CAAC;IAE5D;;;;;;;OAOG;IACH,cAAc,CACZ,QAAQ,EAAE,mBAAmB,EAC7B,UAAU,EAAE,yBAAyB,EACrC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;CACZ;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,oBA4C3B,CAAC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, CodeMatters. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
5
|
+
* in compliance with the License. You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
|
10
|
+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
11
|
+
* or implied. See the License for the specific language governing permissions and limitations under
|
|
12
|
+
* the License.
|
|
13
|
+
*/
|
|
14
|
+
import { create, equals } from "@bufbuild/protobuf";
|
|
15
|
+
import { AgentAcceptedInvocationSchema, AgentCodeRevisionSchema, AgentExecutionScopeSchema, AgentHandlerBindingSchema, AgentHandlerKind, AgentHandlerOrigin, AgentInboxOrderSchema, AgentInvocationKeySchema, AgentPolicyRevisionSchema, AgentSchemaRevisionSchema, AgentSignalKeySchema, } from "@spine-event-engine/proto/generated/spine/server/agent/execution_record_pb.js";
|
|
16
|
+
/**
|
|
17
|
+
* Materializes provider admission without running application handlers.
|
|
18
|
+
*/
|
|
19
|
+
export const AgentAdmission = Object.freeze({
|
|
20
|
+
matchesHandler(accepted, registered, ordinal) {
|
|
21
|
+
return equals(AgentHandlerBindingSchema, accepted, binding(registered, ordinal));
|
|
22
|
+
},
|
|
23
|
+
create(input) {
|
|
24
|
+
const sourceSignal = signalKey(input.signal);
|
|
25
|
+
const bindings = input.handlers.map((handler, ordinal) => binding(handler, ordinal));
|
|
26
|
+
if (bindings.length === 0)
|
|
27
|
+
throw new TypeError("Agent admission requires a selected handler.");
|
|
28
|
+
return create(AgentAcceptedInvocationSchema, {
|
|
29
|
+
key: create(AgentInvocationKeySchema, {
|
|
30
|
+
scope: create(AgentExecutionScopeSchema, {
|
|
31
|
+
stateType: nonblank(input.stateType, "state type"),
|
|
32
|
+
agentKey: nonblank(input.agentKey, "Agent key"),
|
|
33
|
+
}),
|
|
34
|
+
sourceSignal,
|
|
35
|
+
}),
|
|
36
|
+
recipientId: input.recipientId,
|
|
37
|
+
signal: input.signal.kind === "command"
|
|
38
|
+
? { case: "command", value: input.signal.value }
|
|
39
|
+
: { case: "event", value: input.signal.value },
|
|
40
|
+
actor: input.actor,
|
|
41
|
+
order: create(AgentInboxOrderSchema, {
|
|
42
|
+
receivedAt: input.inbox.whenReceived,
|
|
43
|
+
inboxVersion: input.inbox.version,
|
|
44
|
+
sourceSignal,
|
|
45
|
+
}),
|
|
46
|
+
handlers: bindings,
|
|
47
|
+
codeRevision: create(AgentCodeRevisionSchema, {
|
|
48
|
+
value: nonblank(input.codeRevision, "code revision"),
|
|
49
|
+
}),
|
|
50
|
+
schemaRevision: create(AgentSchemaRevisionSchema, {
|
|
51
|
+
value: nonblank(input.schemaRevision, "schema revision"),
|
|
52
|
+
}),
|
|
53
|
+
policyRevision: create(AgentPolicyRevisionSchema, {
|
|
54
|
+
value: nonblank(input.policyRevision, "policy revision"),
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* Requires the original typed signal identity before constructing its durable key.
|
|
61
|
+
*
|
|
62
|
+
* @param signal Accepted Command or Event envelope.
|
|
63
|
+
* @returns Typed source identity.
|
|
64
|
+
*/
|
|
65
|
+
function signalKey(signal) {
|
|
66
|
+
if (signal.kind === "command") {
|
|
67
|
+
const id = signal.value.id;
|
|
68
|
+
if (id === undefined)
|
|
69
|
+
throw new TypeError("Agent admission requires the original typed signal ID.");
|
|
70
|
+
return create(AgentSignalKeySchema, { id: { case: "command", value: id } });
|
|
71
|
+
}
|
|
72
|
+
const id = signal.value.id;
|
|
73
|
+
if (id === undefined)
|
|
74
|
+
throw new TypeError("Agent admission requires the original typed signal ID.");
|
|
75
|
+
return create(AgentSignalKeySchema, {
|
|
76
|
+
id: { case: "event", value: id },
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Converts one generated handler identity without reinterpreting its route.
|
|
81
|
+
*
|
|
82
|
+
* @param registered Selected generated handler metadata.
|
|
83
|
+
* @param ordinal Position within this accepted signal.
|
|
84
|
+
* @returns Complete stored binding.
|
|
85
|
+
*/
|
|
86
|
+
function binding(registered, ordinal) {
|
|
87
|
+
const handler = registered.handler;
|
|
88
|
+
const kind = handler.kind === "command-assignment"
|
|
89
|
+
? AgentHandlerKind.AGENT_HANDLER_COMMAND_ASSIGNMENT
|
|
90
|
+
: handler.kind === "command-reaction"
|
|
91
|
+
? AgentHandlerKind.AGENT_HANDLER_COMMAND_REACTION
|
|
92
|
+
: handler.kind === "event-reaction"
|
|
93
|
+
? AgentHandlerKind.AGENT_HANDLER_EVENT_REACTION
|
|
94
|
+
: undefined;
|
|
95
|
+
if (kind === undefined)
|
|
96
|
+
throw new TypeError("Agent admission selected an unsupported handler.");
|
|
97
|
+
return create(AgentHandlerBindingSchema, {
|
|
98
|
+
ordinal,
|
|
99
|
+
receiverType: registered.entity.schema.typeName,
|
|
100
|
+
methodName: handler.methodName,
|
|
101
|
+
kind,
|
|
102
|
+
signalType: handler.messageFullTypeName,
|
|
103
|
+
origin: handler.origin === "external"
|
|
104
|
+
? AgentHandlerOrigin.AGENT_HANDLER_EXTERNAL
|
|
105
|
+
: AgentHandlerOrigin.AGENT_HANDLER_DOMESTIC,
|
|
106
|
+
parameterCount: handler.parameterCount,
|
|
107
|
+
...(handler.where === undefined
|
|
108
|
+
? {}
|
|
109
|
+
: {
|
|
110
|
+
whereEventField: handler.where.eventField,
|
|
111
|
+
whereEquals: handler.where.equals,
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Requires a nonblank serialized identity or revision.
|
|
117
|
+
*
|
|
118
|
+
* @param value Text to validate.
|
|
119
|
+
* @param label Diagnostic field name.
|
|
120
|
+
* @returns Original checked text.
|
|
121
|
+
*/
|
|
122
|
+
function nonblank(value, label) {
|
|
123
|
+
if (value.trim() === "")
|
|
124
|
+
throw new TypeError(`Agent admission requires ${label}.`);
|
|
125
|
+
return value;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=agent-admission.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-admission.js","sourceRoot":"","sources":["../../src/agent/agent-admission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGpD,OAAO,EACL,6BAA6B,EAC7B,uBAAuB,EACvB,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,EACxB,yBAAyB,EACzB,yBAAyB,EACzB,oBAAoB,GAIrB,MAAM,+EAA+E,CAAC;AAqFvF;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAyB,MAAM,CAAC,MAAM,CAAC;IAChE,cAAc,CACZ,QAA6B,EAC7B,UAAqC,EACrC,OAAe;QAEf,OAAO,MAAM,CAAC,yBAAyB,EAAE,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,CAAC,KAA0B;QAC/B,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QACrF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,SAAS,CAAC,8CAA8C,CAAC,CAAC;QAC/F,OAAO,MAAM,CAAC,6BAA6B,EAAE;YAC3C,GAAG,EAAE,MAAM,CAAC,wBAAwB,EAAE;gBACpC,KAAK,EAAE,MAAM,CAAC,yBAAyB,EAAE;oBACvC,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,YAAY,CAAC;oBAClD,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,WAAW,CAAC;iBAChD,CAAC;gBACF,YAAY;aACb,CAAC;YACF,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,MAAM,EACJ,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS;gBAC7B,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE;gBAChD,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE;YAClD,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,KAAK,EAAE,MAAM,CAAC,qBAAqB,EAAE;gBACnC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,YAAY;gBACpC,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO;gBACjC,YAAY;aACb,CAAC;YACF,QAAQ,EAAE,QAAQ;YAClB,YAAY,EAAE,MAAM,CAAC,uBAAuB,EAAE;gBAC5C,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE,eAAe,CAAC;aACrD,CAAC;YACF,cAAc,EAAE,MAAM,CAAC,yBAAyB,EAAE;gBAChD,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,cAAc,EAAE,iBAAiB,CAAC;aACzD,CAAC;YACF,cAAc,EAAE,MAAM,CAAC,yBAAyB,EAAE;gBAChD,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,cAAc,EAAE,iBAAiB,CAAC;aACzD,CAAC;SACH,CAAC,CAAC;IACL,CAAC;CACF,CAAC,CAAC;AAEH;;;;;GAKG;AACH,SAAS,SAAS,CAAC,MAAqC;IACtD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,IAAI,EAAE,KAAK,SAAS;YAClB,MAAM,IAAI,SAAS,CAAC,wDAAwD,CAAC,CAAC;QAChF,OAAO,MAAM,CAAC,oBAAoB,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IAC3B,IAAI,EAAE,KAAK,SAAS;QAClB,MAAM,IAAI,SAAS,CAAC,wDAAwD,CAAC,CAAC;IAChF,OAAO,MAAM,CAAC,oBAAoB,EAAE;QAClC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;KACjC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,SAAS,OAAO,CAAC,UAAqC,EAAE,OAAe;IACrE,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC;IACnC,MAAM,IAAI,GACR,OAAO,CAAC,IAAI,KAAK,oBAAoB;QACnC,CAAC,CAAC,gBAAgB,CAAC,gCAAgC;QACnD,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,kBAAkB;YACnC,CAAC,CAAC,gBAAgB,CAAC,8BAA8B;YACjD,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,gBAAgB;gBACjC,CAAC,CAAC,gBAAgB,CAAC,4BAA4B;gBAC/C,CAAC,CAAC,SAAS,CAAC;IACpB,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,IAAI,SAAS,CAAC,kDAAkD,CAAC,CAAC;IAChG,OAAO,MAAM,CAAC,yBAAyB,EAAE;QACvC,OAAO;QACP,YAAY,EAAE,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ;QAC/C,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,IAAI;QACJ,UAAU,EAAE,OAAO,CAAC,mBAAmB;QACvC,MAAM,EACJ,OAAO,CAAC,MAAM,KAAK,UAAU;YAC3B,CAAC,CAAC,kBAAkB,CAAC,sBAAsB;YAC3C,CAAC,CAAC,kBAAkB,CAAC,sBAAsB;QAC/C,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS;YAC7B,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC;gBACE,eAAe,EAAE,OAAO,CAAC,KAAK,CAAC,UAAU;gBACzC,WAAW,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM;aAClC,CAAC;KACP,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,SAAS,QAAQ,CAAC,KAAa,EAAE,KAAa;IAC5C,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,4BAA4B,KAAK,GAAG,CAAC,CAAC;IACnF,OAAO,KAAK,CAAC;AACf,CAAC"}
|