ankka 0.10.0 → 0.12.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.
Files changed (94) hide show
  1. package/README.md +1 -0
  2. package/dist/_proto/ankka/protocol/v1/agent_pb.d.ts +35 -0
  3. package/dist/_proto/ankka/protocol/v1/agent_pb.js +8 -1
  4. package/dist/_proto/ankka/protocol/v1/client_pb.d.ts +858 -2
  5. package/dist/_proto/ankka/protocol/v1/client_pb.js +184 -9
  6. package/dist/_proto/ankka/protocol/v1/consumer_pb.d.ts +10 -1
  7. package/dist/_proto/ankka/protocol/v1/consumer_pb.js +1 -1
  8. package/dist/_proto/ankka/protocol/v1/discovery_pb.d.ts +373 -0
  9. package/dist/_proto/ankka/protocol/v1/discovery_pb.js +81 -16
  10. package/dist/_proto/ankka/protocol/v1/endpoint_pb.d.ts +210 -0
  11. package/dist/_proto/ankka/protocol/v1/endpoint_pb.js +35 -5
  12. package/dist/_proto/ankka/protocol/v1/event_sourced_pb.d.ts +86 -0
  13. package/dist/_proto/ankka/protocol/v1/event_sourced_pb.js +11 -1
  14. package/dist/_proto/ankka/protocol/v1/payload_pb.d.ts +61 -0
  15. package/dist/_proto/ankka/protocol/v1/payload_pb.js +18 -1
  16. package/dist/_proto/ankka/protocol/v1/view_pb.d.ts +70 -1
  17. package/dist/_proto/ankka/protocol/v1/view_pb.js +11 -1
  18. package/dist/_proto/ankka/protocol/v1/wasm_pb.d.ts +12 -0
  19. package/dist/_proto/ankka/protocol/v1/wasm_pb.js +1 -1
  20. package/dist/_proto/ankka/protocol/v1/workflow_pb.d.ts +7 -0
  21. package/dist/_proto/ankka/protocol/v1/workflow_pb.js +1 -1
  22. package/dist/agent.d.ts +15 -1
  23. package/dist/agent.js +20 -0
  24. package/dist/approvals.d.ts +47 -0
  25. package/dist/approvals.js +57 -0
  26. package/dist/autonomous.d.ts +23 -1
  27. package/dist/autonomous.js +30 -1
  28. package/dist/client.d.ts +188 -7
  29. package/dist/client.js +490 -21
  30. package/dist/consumer.d.ts +42 -3
  31. package/dist/consumer.js +35 -1
  32. package/dist/context.d.ts +29 -1
  33. package/dist/context.js +5 -2
  34. package/dist/contract.d.ts +40 -0
  35. package/dist/contract.js +60 -0
  36. package/dist/effects/common.d.ts +7 -0
  37. package/dist/effects/common.js +9 -1
  38. package/dist/effects/eventSourced.d.ts +26 -1
  39. package/dist/effects/eventSourced.js +58 -5
  40. package/dist/effects/keyed.d.ts +33 -0
  41. package/dist/effects/keyed.js +41 -0
  42. package/dist/endpoint.d.ts +10 -1
  43. package/dist/endpoint.js +20 -0
  44. package/dist/eventSourcedEntity.d.ts +8 -3
  45. package/dist/graph.d.ts +24 -2
  46. package/dist/graph.js +27 -1
  47. package/dist/handlers.d.ts +10 -2
  48. package/dist/handlers.js +6 -2
  49. package/dist/index.d.ts +15 -6
  50. package/dist/index.js +12 -3
  51. package/dist/keyedView.d.ts +59 -0
  52. package/dist/keyedView.js +73 -0
  53. package/dist/kinds.js +2 -0
  54. package/dist/mcp.d.ts +57 -0
  55. package/dist/mcp.js +64 -0
  56. package/dist/routes.d.ts +44 -4
  57. package/dist/routes.js +43 -4
  58. package/dist/server/agent.js +12 -4
  59. package/dist/server/discovery.d.ts +17 -1
  60. package/dist/server/discovery.js +182 -1
  61. package/dist/server/eventSourced.d.ts +4 -1
  62. package/dist/server/eventSourced.js +24 -6
  63. package/dist/server/http.d.ts +2 -1
  64. package/dist/server/http.js +80 -4
  65. package/dist/server/stateless.js +42 -3
  66. package/dist/server/workflow.js +5 -1
  67. package/dist/service.d.ts +46 -2
  68. package/dist/service.js +235 -15
  69. package/dist/services.d.ts +137 -0
  70. package/dist/services.js +259 -0
  71. package/dist/socket.d.ts +15 -0
  72. package/dist/socket.js +25 -0
  73. package/dist/spec.d.ts +1 -1
  74. package/dist/spec.js +94 -15
  75. package/dist/standing.d.ts +18 -0
  76. package/dist/standing.js +26 -0
  77. package/dist/startFrom.d.ts +36 -0
  78. package/dist/startFrom.js +51 -0
  79. package/dist/testkit/index.d.ts +2 -2
  80. package/dist/testkit/index.js +1 -1
  81. package/dist/testkit/integration.js +5 -0
  82. package/dist/testkit/kinds.d.ts +50 -5
  83. package/dist/testkit/kinds.js +208 -35
  84. package/dist/testkit/unit.d.ts +41 -3
  85. package/dist/testkit/unit.js +87 -10
  86. package/dist/timedAction.d.ts +17 -2
  87. package/dist/timedAction.js +33 -1
  88. package/dist/version.d.ts +1 -1
  89. package/dist/version.js +1 -1
  90. package/dist/view.d.ts +48 -1
  91. package/dist/view.js +18 -1
  92. package/dist/workflow.d.ts +18 -1
  93. package/dist/workflow.js +39 -0
  94. package/package.json +3 -2
@@ -5,7 +5,7 @@
5
5
  // `createHttpDispatcher` is the whole behaviour; the Connect servicer and the endpoint unit testkit both
6
6
  // call it, so a test cannot pass on a path the sidecar would not take.
7
7
  import { create } from "@bufbuild/protobuf";
8
- import { Http, HttpReplySchema, StreamFrameSchema } from "../_proto/ankka/protocol/v1/endpoint_pb.js";
8
+ import { Http, HttpReplySchema, SocketOutSchema, StreamFrameSchema, } from "../_proto/ankka/protocol/v1/endpoint_pb.js";
9
9
  import { codecFor } from "../codec.js";
10
10
  import { Headers, Query, metadataFromProto, withRequest } from "../context.js";
11
11
  import { CommandError, ErrorCode, httpStatusOf } from "../effects/common.js";
@@ -13,6 +13,7 @@ import { DecodingError } from "../json.js";
13
13
  import { errorCodeToProto } from "../kinds.js";
14
14
  import { HttpProblem } from "../routes.js";
15
15
  import { done, resolve } from "../schema.js";
16
+ import { SocketClosed, socketOf } from "../socket.js";
16
17
  import { AsyncQueue } from "./queue.js";
17
18
  const utf8 = new TextEncoder();
18
19
  function textResponse(status, text) {
@@ -28,7 +29,15 @@ function principalOf(req) {
28
29
  const p = req.principal;
29
30
  if (!p)
30
31
  return null;
31
- return Object.freeze({ subject: p.subject, name: p.name ?? null, email: p.email ?? null, emailVerified: p.emailVerified, roles: Object.freeze([...p.roles]) });
32
+ return Object.freeze({
33
+ subject: p.subject,
34
+ name: p.name ?? null,
35
+ email: p.email ?? null,
36
+ emailVerified: p.emailVerified,
37
+ roles: Object.freeze([...p.roles]),
38
+ claims: Object.freeze({ ...p.claims }),
39
+ issuer: p.issuer ?? null,
40
+ });
32
41
  }
33
42
  /** The caller the sidecar established; a sidecar that predates protocol 1.1 sends none, which reads as local. */
34
43
  function callerOf(req) {
@@ -38,6 +47,8 @@ function callerOf(req) {
38
47
  return Object.freeze({ kind: "gateway" });
39
48
  case "service":
40
49
  return Object.freeze({ kind: "service", project: kind.value.project, name: kind.value.name });
50
+ case "machine":
51
+ return Object.freeze({ kind: "machine", organization: kind.value.organization, name: kind.value.name });
41
52
  default:
42
53
  return Object.freeze({ kind: "local" });
43
54
  }
@@ -69,6 +80,7 @@ function encodeResult(route, result) {
69
80
  const contentType = codec.contentType === "text/plain" ? "text/plain; charset=utf-8" : codec.contentType;
70
81
  return create(HttpReplySchema, { message: { case: "response", value: { status: 200, contentType, body: codec.encode(result), headers: [] } } });
71
82
  }
83
+ const NEEDS_SOCKETS = "a socket route needs protocol 1.9; this runtime asked for a request";
72
84
  /** The behaviour behind `Http.Handle` and `Http.HandleStream`, over the registry's endpoints. */
73
85
  export function createHttpDispatcher(ctx) {
74
86
  const instances = new Map();
@@ -118,6 +130,8 @@ export function createHttpDispatcher(ctx) {
118
130
  const prep = prepare(req);
119
131
  if (!prep.ok)
120
132
  return prep.reply;
133
+ if (prep.prepared.route.socket)
134
+ return failureReply(NEEDS_SOCKETS);
121
135
  const { route, instance, request, body } = prep.prepared;
122
136
  try {
123
137
  const result = await withRequest(request, () => route.run(instance, request, body));
@@ -135,13 +149,21 @@ export function createHttpDispatcher(ctx) {
135
149
  return;
136
150
  }
137
151
  const { route, instance, request } = prep.prepared;
152
+ if (route.socket) {
153
+ yield create(StreamFrameSchema, { frame: { case: "failed", value: { message: NEEDS_SOCKETS, code: errorCodeToProto(ErrorCode.Internal) } } });
154
+ return;
155
+ }
138
156
  // Produce inside the request's async context, consume here: the handler's `this.request` stays visible.
139
157
  const queue = new AsyncQueue();
140
158
  void withRequest(request, async () => {
141
159
  try {
142
160
  const frames = (await route.run(instance, request, undefined));
143
- for await (const text of frames)
144
- queue.push(create(StreamFrameSchema, { frame: { case: "text", value: text } }));
161
+ for await (const part of frames) {
162
+ if (typeof part === "string")
163
+ queue.push(create(StreamFrameSchema, { frame: { case: "text", value: part } }));
164
+ else
165
+ queue.push(create(StreamFrameSchema, { frame: { case: "event", value: { name: part.name, data: JSON.stringify(part.value, (_k, v) => (typeof v === "bigint" ? v.toString() : v)) } } }));
166
+ }
145
167
  queue.push(create(StreamFrameSchema, { frame: { case: "completed", value: {} } }));
146
168
  }
147
169
  catch (e) {
@@ -155,6 +177,59 @@ export function createHttpDispatcher(ctx) {
155
177
  });
156
178
  yield* queue;
157
179
  },
180
+ // An open socket: `open` first, then frames until `closed`. The requests are read only when the
181
+ // handler asks for a frame, so a handler that does not read is not read for, and the sidecar's flow
182
+ // control holds the client back.
183
+ async *handleSocket(requests) {
184
+ const incoming = requests[Symbol.asyncIterator]();
185
+ const failed = (message, code = ErrorCode.Internal) => create(SocketOutSchema, { message: { case: "failed", value: { message, code: errorCodeToProto(code) } } });
186
+ const first = await incoming.next();
187
+ if (first.done || first.value.message.case !== "open") {
188
+ yield failed("a socket opens with open");
189
+ return;
190
+ }
191
+ const prep = prepare(first.value.message.value);
192
+ if (!prep.ok || !prep.prepared.route.socket) {
193
+ yield failed("unknown socket route", ErrorCode.NotFound);
194
+ return;
195
+ }
196
+ const { route, instance, request } = prep.prepared;
197
+ const outgoing = new AsyncQueue();
198
+ let closed = false;
199
+ const receive = async () => {
200
+ if (closed)
201
+ return undefined;
202
+ const next = await incoming.next();
203
+ const message = next.done ? undefined : next.value.message;
204
+ if (message?.case === "frame" && message.value.kind.case === "text")
205
+ return message.value.kind.value;
206
+ closed = true; // closed, the stream's end, or a kind this SDK does not know
207
+ return undefined;
208
+ };
209
+ const send = async (text) => {
210
+ if (closed)
211
+ throw new SocketClosed();
212
+ outgoing.push(create(SocketOutSchema, { message: { case: "frame", value: { kind: { case: "text", value: text } } } }));
213
+ };
214
+ void withRequest(request, async () => {
215
+ try {
216
+ await route.run(instance, request, socketOf(receive, send));
217
+ outgoing.push(create(SocketOutSchema, { message: { case: "completed", value: {} } }));
218
+ }
219
+ catch (e) {
220
+ if (e instanceof SocketClosed)
221
+ outgoing.push(create(SocketOutSchema, { message: { case: "completed", value: {} } }));
222
+ else {
223
+ ctx.log(`ankka: SOCKET ${route.template} threw: ${messageOf(e)}`);
224
+ outgoing.push(failed(messageOf(e)));
225
+ }
226
+ }
227
+ finally {
228
+ outgoing.close();
229
+ }
230
+ });
231
+ yield* outgoing;
232
+ },
158
233
  };
159
234
  }
160
235
  export function httpRoutes(router, ctx) {
@@ -162,5 +237,6 @@ export function httpRoutes(router, ctx) {
162
237
  router.service(Http, {
163
238
  handle: (req) => dispatcher.handle(req),
164
239
  handleStream: (req) => dispatcher.handleStream(req),
240
+ handleSocket: (requests) => dispatcher.handleSocket(requests),
165
241
  });
166
242
  }
@@ -8,16 +8,55 @@ import { TimedAction as TimedActionService, TimedActionEffectSchema } from "../_
8
8
  import { codecFor } from "../codec.js";
9
9
  import { metadataFromProto, metadataToProto } from "../context.js";
10
10
  import { ErrorCode } from "../effects/common.js";
11
+ import { clientRows } from "../keyedView.js";
11
12
  import { ProtocolVersionError, requireSeveralMessages } from "../consumer.js";
12
13
  import { GRAPH_DELTA_SCHEMA, deltaRecords } from "../graph.js";
13
14
  import { JSON_CONTENT } from "../codec.js";
14
15
  import { errorCodeToProto } from "../kinds.js";
15
16
  import { decodePayload, encodePayload } from "./payloads.js";
16
17
  import { PayloadSchema } from "../_proto/ankka/protocol/v1/payload_pb.js";
18
+ import { standingFromProto } from "../standing.js";
17
19
  function messageOf(e) {
18
20
  return e instanceof Error ? `${e.name}: ${e.message}` : String(e);
19
21
  }
22
+ /**
23
+ * A keyed view's change: sent with the component it came from and no row, answered with the rows the
24
+ * source's handler names. The view reads its own rows through the client, on its own id.
25
+ */
26
+ async function handleKeyedView(req, sourceId, ctx) {
27
+ const registered = ctx.registry.of("keyed-view", req.componentId);
28
+ if (!registered)
29
+ throw new ConnectError(`no keyed view ${JSON.stringify(req.componentId)} is registered`, Code.NotFound);
30
+ const source = registered.sources.get(sourceId);
31
+ if (!source)
32
+ throw new ConnectError(`keyed view ${registered.id} reads no ${JSON.stringify(sourceId)}`, Code.NotFound);
33
+ const metadata = metadataFromProto(req.metadata);
34
+ const view = new registered.cls();
35
+ try {
36
+ const client = ctx.client.withMetadata(metadata);
37
+ view._bind(metadata, client, clientRows(client, registered.id, registered.rowCodec), standingFromProto(req.standing));
38
+ const effect = (req.deleted
39
+ ? source.deleted
40
+ ? await source.deleted(view)
41
+ : undefined
42
+ : await source.onChange(view, decodePayload(source.eventCodec, req.event)));
43
+ if (effect !== undefined && effect?.kind !== "rows")
44
+ throw new TypeError(`${registered.id}'s handler for ${sourceId} returned something that is not a keyed view effect`);
45
+ const changes = (effect?.changes ?? []).map((c) => "deleted" in c
46
+ ? { key: c.key, change: { case: "delete", value: {} } }
47
+ : { key: c.key, change: { case: "upsert", value: encodePayload(registered.rowCodec, c.row) } });
48
+ return create(ViewEffectSchema, { effect: { case: "rows", value: { changes } } });
49
+ }
50
+ catch (e) {
51
+ if (e instanceof ConnectError)
52
+ throw e;
53
+ ctx.log(`ankka: keyed view ${registered.id} on ${sourceId} ${metadata["ce-subject"] ?? "?"} threw: ${messageOf(e)}`);
54
+ throw new ConnectError(messageOf(e), Code.Internal);
55
+ }
56
+ }
20
57
  export async function handleView(req, ctx) {
58
+ if (req.sourceId !== undefined)
59
+ return handleKeyedView(req, req.sourceId, ctx);
21
60
  const registered = ctx.registry.of("view", req.componentId);
22
61
  if (!registered)
23
62
  throw new ConnectError(`no view ${JSON.stringify(req.componentId)} is registered`, Code.NotFound);
@@ -25,7 +64,7 @@ export async function handleView(req, ctx) {
25
64
  const view = new registered.cls();
26
65
  try {
27
66
  const row = req.row ? decodePayload(registered.rowCodec, req.row) : null;
28
- view._bind(row, metadata, ctx.client.withMetadata(metadata));
67
+ view._bind(row, metadata, ctx.client.withMetadata(metadata), standingFromProto(req.standing));
29
68
  const effect = req.deleted ? await view.onDelete() : await view.onChange(decodePayload(registered.eventCodec, req.event));
30
69
  switch (effect.kind) {
31
70
  case "update-row":
@@ -64,7 +103,7 @@ function produceAll(request, messages) {
64
103
  }
65
104
  async function graphEffect(registered, req, metadata, ctx) {
66
105
  const consumer = new registered.cls();
67
- consumer._bind(metadata, ctx.client.withMetadata(metadata));
106
+ consumer._bind(metadata, ctx.client.withMetadata(metadata), standingFromProto(req.standing));
68
107
  const effect = req.deleted ? await consumer.onDelete() : await consumer.onMessage(decodePayload(registered.messageCodec, req.message));
69
108
  switch (effect.kind) {
70
109
  case "publish":
@@ -83,7 +122,7 @@ async function graphEffect(registered, req, metadata, ctx) {
83
122
  }
84
123
  async function consumerEffect(registered, req, metadata, ctx) {
85
124
  const consumer = new registered.cls();
86
- consumer._bind(metadata, ctx.client.withMetadata(metadata));
125
+ consumer._bind(metadata, ctx.client.withMetadata(metadata), standingFromProto(req.standing));
87
126
  const effect = req.deleted ? await consumer.onDelete() : await consumer.onMessage(decodePayload(registered.messageCodec, req.message));
88
127
  const outCodec = () => {
89
128
  if (!registered.outCodec)
@@ -114,7 +114,11 @@ class WorkflowStream {
114
114
  return failure(run.id, { message: `${registered.id}/${run.step}: the input could not be decoded: ${messageOf(e)}`, code: ErrorCode.BadRequest });
115
115
  }
116
116
  let effect;
117
- fresh._bindCommand(this.state, commandContext(registered.id, this.entityId, 0n, {}), ctx.client);
117
+ // What the sidecar says about this step: its trace, and the step as the caller of whatever it calls.
118
+ // Carried on the step's calls as a command's is; a sidecar before 1.3 sends none.
119
+ const metadata = metadataFromProto(run.metadata);
120
+ fresh._bindCommand(this.state, commandContext(registered.id, this.entityId, 0n, metadata), ctx.client.withMetadata(metadata));
121
+ fresh._enterStep();
118
122
  try {
119
123
  effect = (await step.run(fresh, input));
120
124
  }
package/dist/service.d.ts CHANGED
@@ -1,12 +1,16 @@
1
+ import { type StartFrom } from "./startFrom.ts";
2
+ import { Contract, type Publication } from "./contract.ts";
1
3
  import { type Codec } from "./codec.ts";
2
4
  import { EventSourcedEntity, type EventSourcedEntityClass } from "./eventSourcedEntity.ts";
3
5
  import { KeyValueEntity, type KeyValueEntityClass } from "./keyValueEntity.ts";
4
6
  import { Workflow, type WorkflowClass } from "./workflow.ts";
5
- import { View, type ViewClass } from "./view.ts";
7
+ import { View, type DeclaredQuery, type ViewClass } from "./view.ts";
8
+ import { KeyedView, type KeyedViewClass } from "./keyedView.ts";
6
9
  import { Consumer, type ConsumerClass } from "./consumer.ts";
7
10
  import { GraphConsumer, type GraphConsumerClass } from "./graph.ts";
8
11
  import { TimedAction, type TimedActionClass } from "./timedAction.ts";
9
12
  import { Agent, type AgentClass } from "./agent.ts";
13
+ import { type McpServerRef, type ResultGuardrailRef } from "./mcp.ts";
10
14
  import { AutonomousAgent, type AutonomousAgentClass, type TaskType } from "./autonomous.ts";
11
15
  import { Endpoint, type EndpointClass } from "./endpoint.ts";
12
16
  import type { GuardrailRef, HandlerRef, ToolRef } from "./handlers.ts";
@@ -24,6 +28,8 @@ export interface RegisteredEventSourced {
24
28
  readonly eventCodec: Codec<any>;
25
29
  readonly handlers: ReadonlyMap<string, HandlerRef<any, any, any, any>>;
26
30
  readonly snapshotEvery: number;
31
+ /** Declared replicated (1.19). */
32
+ readonly replicated: boolean;
27
33
  }
28
34
  export interface RegisteredKeyValue {
29
35
  readonly kind: "key-value";
@@ -49,6 +55,15 @@ export type Source = {
49
55
  };
50
56
  } | {
51
57
  readonly topic: string;
58
+ readonly startFrom?: StartFrom;
59
+ /** The contract the topic is expected to carry. */
60
+ readonly contract?: Contract;
61
+ /** The declared broker the topic is on; absent is the installation's. */
62
+ readonly broker?: string;
63
+ /** Another project's topic: the project whose topic it is (1.15). */
64
+ readonly project?: string;
65
+ /** Partitions handled at once, each in order. */
66
+ readonly parallel?: boolean;
52
67
  };
53
68
  export interface RegisteredView {
54
69
  readonly kind: "view";
@@ -58,6 +73,25 @@ export interface RegisteredView {
58
73
  readonly eventCodec: Codec<any>;
59
74
  readonly rowCodec: Codec<any>;
60
75
  readonly queries: readonly string[];
76
+ readonly version: number | undefined;
77
+ readonly declared: readonly DeclaredQuery[];
78
+ }
79
+ /** One source of a keyed view: the entity it reads, how its changes decode, and its handlers. */
80
+ export interface RegisteredKeyedSource {
81
+ readonly id: string;
82
+ readonly kind: ComponentKind;
83
+ readonly eventCodec: Codec<any>;
84
+ readonly onChange: (view: any, event: any) => unknown;
85
+ readonly deleted: ((view: any) => unknown) | undefined;
86
+ }
87
+ export interface RegisteredKeyedView {
88
+ readonly kind: "keyed-view";
89
+ readonly id: string;
90
+ readonly cls: KeyedViewClass<any, any>;
91
+ readonly sources: ReadonlyMap<string, RegisteredKeyedSource>;
92
+ readonly rowCodec: Codec<any>;
93
+ readonly version: number | undefined;
94
+ readonly declared: readonly DeclaredQuery[];
61
95
  }
62
96
  export interface RegisteredConsumer {
63
97
  readonly kind: "consumer";
@@ -67,8 +101,13 @@ export interface RegisteredConsumer {
67
101
  readonly messageCodec: Codec<any>;
68
102
  readonly outCodec: Codec<any> | undefined;
69
103
  readonly producesTo: string | undefined;
104
+ /** The publication as declared: the topic with the contract stated for it and its broker. */
105
+ readonly produces: Publication | undefined;
70
106
  /** A graph consumer: its handlers return elements, each published as a delta under its element key. */
71
107
  readonly graph: boolean;
108
+ readonly version: number | undefined;
109
+ /** Given a replicated entity's mirrored changes too (1.19). */
110
+ readonly mirroredChanges: boolean;
72
111
  }
73
112
  export interface RegisteredTimedAction {
74
113
  readonly kind: "timed-action";
@@ -83,6 +122,8 @@ export interface RegisteredAgent {
83
122
  readonly handlers: ReadonlyMap<string, HandlerRef<any, any, any, any>>;
84
123
  readonly tools: ReadonlyMap<string, ToolRef<any, any>>;
85
124
  readonly guardrails: ReadonlyMap<string, GuardrailRef>;
125
+ readonly mcpServers: ReadonlyMap<string, McpServerRef>;
126
+ readonly resultGuardrails: ReadonlyMap<string, ResultGuardrailRef>;
86
127
  readonly role: string;
87
128
  readonly maxToolCallSteps: number;
88
129
  }
@@ -92,9 +133,11 @@ export interface RegisteredAutonomousAgent {
92
133
  readonly cls: AutonomousAgentClass<any>;
93
134
  readonly tools: ReadonlyMap<string, ToolRef<any, any>>;
94
135
  readonly guardrails: ReadonlyMap<string, GuardrailRef>;
136
+ readonly mcpServers: ReadonlyMap<string, McpServerRef>;
137
+ readonly resultGuardrails: ReadonlyMap<string, ResultGuardrailRef>;
95
138
  readonly taskTypes: ReadonlyMap<string, TaskType<any>>;
96
139
  }
97
- export type RegisteredComponent = RegisteredEventSourced | RegisteredKeyValue | RegisteredWorkflow | RegisteredView | RegisteredConsumer | RegisteredTimedAction | RegisteredAgent | RegisteredAutonomousAgent;
140
+ export type RegisteredComponent = RegisteredEventSourced | RegisteredKeyValue | RegisteredWorkflow | RegisteredView | RegisteredKeyedView | RegisteredConsumer | RegisteredTimedAction | RegisteredAgent | RegisteredAutonomousAgent;
98
141
  export interface RegisteredEndpoint {
99
142
  readonly id: string;
100
143
  readonly cls: EndpointClass<any>;
@@ -136,6 +179,7 @@ export declare class ServiceBuilder {
136
179
  register<S, C extends KeyValueEntity<S>>(cls: KeyValueEntityClass<S, C>): this;
137
180
  register<S, C extends Workflow<S>>(cls: WorkflowClass<S, C>): this;
138
181
  register<E, Row, C extends View<E, Row>>(cls: ViewClass<E, Row, C>): this;
182
+ register<Row, C extends KeyedView<Row>>(cls: KeyedViewClass<Row, C>): this;
139
183
  register<M, Out, C extends Consumer<M, Out>>(cls: ConsumerClass<M, Out, C>): this;
140
184
  register<M, C extends GraphConsumer<M>>(cls: GraphConsumerClass<M, C>): this;
141
185
  register<C extends TimedAction>(cls: TimedActionClass<C>): this;