@mozaik-ai/core 4.0.0-beta.6 → 4.0.0-beta.7

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/dist/index.d.mts CHANGED
@@ -129,6 +129,46 @@ interface FunctionTool {
129
129
  }
130
130
  type Tool = FunctionTool;
131
131
 
132
+ type SituationContext$1<TEvent extends SemanticEvent = SemanticEvent> = {
133
+ readonly event: TEvent;
134
+ readonly participant: Participant;
135
+ };
136
+ declare abstract class SituationSpecification<TEvent extends SemanticEvent = SemanticEvent> {
137
+ abstract isSatisfiedBy(situationContext: SituationContext$1<TEvent>): boolean;
138
+ and(other: SituationSpecification<TEvent>): SituationSpecification<TEvent>;
139
+ or(other: SituationSpecification<TEvent>): SituationSpecification<TEvent>;
140
+ not(): SituationSpecification<TEvent>;
141
+ }
142
+
143
+ interface SituationHandler {
144
+ readonly specification: SituationSpecification;
145
+ readonly processor: SituationProcessor;
146
+ }
147
+ type SituationContext<TEvent extends SemanticEvent = SemanticEvent> = {
148
+ readonly event: TEvent;
149
+ readonly participant: Participant;
150
+ };
151
+ interface SituationProcessor {
152
+ apply(context: SituationContext): void | Promise<void>;
153
+ }
154
+
155
+ type ParticipantRole = "agent" | "human";
156
+ type ParticipantManifest = {
157
+ readonly id: string;
158
+ readonly name: string;
159
+ readonly role: ParticipantRole;
160
+ readonly capabilities?: readonly string[];
161
+ };
162
+ declare abstract class Participant {
163
+ private readonly manifest;
164
+ private handlers;
165
+ protected constructor(manifest: ParticipantManifest, handlers: SituationHandler[]);
166
+ getManifest(): ParticipantManifest;
167
+ getId(): string;
168
+ getHandlers(): SituationHandler[];
169
+ setHandlers(handlers: SituationHandler[]): void;
170
+ }
171
+
132
172
  declare class SemanticEvent<TType extends string = string, TPayload = unknown> {
133
173
  readonly type: TType;
134
174
  readonly producerId: string;
@@ -141,6 +181,71 @@ declare class SemanticEvent<TType extends string = string, TPayload = unknown> {
141
181
  interface FunctionCallRunner {
142
182
  run(call: FunctionCallItem, tool: Tool): Promise<FunctionCallOutputItem>;
143
183
  }
184
+ interface FunctionCallParams {
185
+ call: FunctionCallItem;
186
+ inferenceInput: InferenceInput;
187
+ }
188
+
189
+ type LoopStateId = "context_update" | "inference" | "inference_streaming" | "function_call" | "model_message" | "idle";
190
+ type ReceivedMessage = {
191
+ content: string;
192
+ input: InferenceInput;
193
+ };
194
+ interface FunctionCallExecutionOutput {
195
+ item: FunctionCallOutputItem;
196
+ }
197
+ interface ModelMessageParams {
198
+ answer: ModelMessageItem;
199
+ }
200
+ interface LoopStateContract {
201
+ context_update: {
202
+ input: ReceivedMessage;
203
+ output: InferenceInput;
204
+ };
205
+ inference: {
206
+ input: InferenceInput;
207
+ output: InferenceOutput;
208
+ };
209
+ inference_streaming: {
210
+ input: InferenceInput;
211
+ output: InferenceOutput;
212
+ };
213
+ function_call: {
214
+ input: FunctionCallParams;
215
+ output: FunctionCallExecutionOutput;
216
+ };
217
+ model_message: {
218
+ input: ModelMessageParams;
219
+ output: void;
220
+ };
221
+ interception: {
222
+ input: InterceptionParams;
223
+ output: InterceptionOutput;
224
+ };
225
+ idle: {
226
+ input: undefined;
227
+ output: void;
228
+ };
229
+ }
230
+ type InterceptionOutput = {
231
+ type: "continue";
232
+ transition: LoopTransition;
233
+ } | {
234
+ type: "pause";
235
+ pendingTransition: LoopTransition;
236
+ } | {
237
+ type: "stop";
238
+ reason?: string;
239
+ };
240
+ interface InterceptionParams {
241
+ pendingTransition: LoopTransition;
242
+ }
243
+ type LoopTransition<TStateId extends LoopStateId = LoopStateId> = {
244
+ [K in TStateId]: {
245
+ nextStateId: K;
246
+ input: LoopStateContract[K]["input"];
247
+ };
248
+ }[TStateId];
144
249
 
145
250
  type InferenceInput = {
146
251
  model: string;
@@ -299,46 +404,6 @@ declare class SystemMessageItem extends ContextItem {
299
404
  }): SystemMessageItem;
300
405
  }
301
406
 
302
- type SituationContext$1<TEvent extends SemanticEvent = SemanticEvent> = {
303
- readonly event: TEvent;
304
- readonly participant: Participant;
305
- };
306
- declare abstract class SituationSpecification<TEvent extends SemanticEvent = SemanticEvent> {
307
- abstract isSatisfiedBy(situationContext: SituationContext$1<TEvent>): boolean;
308
- and(other: SituationSpecification<TEvent>): SituationSpecification<TEvent>;
309
- or(other: SituationSpecification<TEvent>): SituationSpecification<TEvent>;
310
- not(): SituationSpecification<TEvent>;
311
- }
312
-
313
- interface SituationHandler {
314
- readonly specification: SituationSpecification;
315
- readonly processor: SituationProcessor;
316
- }
317
- type SituationContext<TEvent extends SemanticEvent = SemanticEvent> = {
318
- readonly event: TEvent;
319
- readonly participant: Participant;
320
- };
321
- interface SituationProcessor {
322
- apply(context: SituationContext): void | Promise<void>;
323
- }
324
-
325
- type ParticipantRole = "agent" | "human";
326
- type ParticipantManifest = {
327
- readonly id: string;
328
- readonly name: string;
329
- readonly role: ParticipantRole;
330
- readonly capabilities?: readonly string[];
331
- };
332
- declare abstract class Participant {
333
- private readonly manifest;
334
- private handlers;
335
- protected constructor(manifest: ParticipantManifest, handlers: SituationHandler[]);
336
- getManifest(): ParticipantManifest;
337
- getId(): string;
338
- getHandlers(): SituationHandler[];
339
- setHandlers(handlers: SituationHandler[]): void;
340
- }
341
-
342
407
  declare class Memory {
343
408
  private readonly context;
344
409
  private constructor();
@@ -394,6 +459,11 @@ declare abstract class RuntimeState {
394
459
  getParticipants(): readonly Participant[];
395
460
  }
396
461
 
462
+ interface InterceptionHandler {
463
+ isSatisfiedBy(transition: LoopTransition): boolean;
464
+ handle(transition: LoopTransition): Promise<LoopTransition>;
465
+ }
466
+
397
467
  declare class EventProcessor {
398
468
  process(event: SemanticEvent, consumer: Participant): void;
399
469
  }
@@ -427,7 +497,7 @@ declare function defineRuntime<TRuntimeState extends RuntimeState>(): {
427
497
  leave: (participant: Participant) => void;
428
498
  sendMessage: (message: string, senderId: string) => void;
429
499
  sendEvent: (event: SemanticEvent, senderId: string) => void;
430
- runLoop: (agentId: string, message: string, inferenceInput: InferenceInput) => void;
500
+ runLoop: (agentId: string, message: string, inferenceInput: InferenceInput, interceptionHandler: InterceptionHandler) => void;
431
501
  };
432
502
 
433
503
  declare const supportedModels: GenerativeModel[];
package/dist/index.d.ts CHANGED
@@ -129,6 +129,46 @@ interface FunctionTool {
129
129
  }
130
130
  type Tool = FunctionTool;
131
131
 
132
+ type SituationContext$1<TEvent extends SemanticEvent = SemanticEvent> = {
133
+ readonly event: TEvent;
134
+ readonly participant: Participant;
135
+ };
136
+ declare abstract class SituationSpecification<TEvent extends SemanticEvent = SemanticEvent> {
137
+ abstract isSatisfiedBy(situationContext: SituationContext$1<TEvent>): boolean;
138
+ and(other: SituationSpecification<TEvent>): SituationSpecification<TEvent>;
139
+ or(other: SituationSpecification<TEvent>): SituationSpecification<TEvent>;
140
+ not(): SituationSpecification<TEvent>;
141
+ }
142
+
143
+ interface SituationHandler {
144
+ readonly specification: SituationSpecification;
145
+ readonly processor: SituationProcessor;
146
+ }
147
+ type SituationContext<TEvent extends SemanticEvent = SemanticEvent> = {
148
+ readonly event: TEvent;
149
+ readonly participant: Participant;
150
+ };
151
+ interface SituationProcessor {
152
+ apply(context: SituationContext): void | Promise<void>;
153
+ }
154
+
155
+ type ParticipantRole = "agent" | "human";
156
+ type ParticipantManifest = {
157
+ readonly id: string;
158
+ readonly name: string;
159
+ readonly role: ParticipantRole;
160
+ readonly capabilities?: readonly string[];
161
+ };
162
+ declare abstract class Participant {
163
+ private readonly manifest;
164
+ private handlers;
165
+ protected constructor(manifest: ParticipantManifest, handlers: SituationHandler[]);
166
+ getManifest(): ParticipantManifest;
167
+ getId(): string;
168
+ getHandlers(): SituationHandler[];
169
+ setHandlers(handlers: SituationHandler[]): void;
170
+ }
171
+
132
172
  declare class SemanticEvent<TType extends string = string, TPayload = unknown> {
133
173
  readonly type: TType;
134
174
  readonly producerId: string;
@@ -141,6 +181,71 @@ declare class SemanticEvent<TType extends string = string, TPayload = unknown> {
141
181
  interface FunctionCallRunner {
142
182
  run(call: FunctionCallItem, tool: Tool): Promise<FunctionCallOutputItem>;
143
183
  }
184
+ interface FunctionCallParams {
185
+ call: FunctionCallItem;
186
+ inferenceInput: InferenceInput;
187
+ }
188
+
189
+ type LoopStateId = "context_update" | "inference" | "inference_streaming" | "function_call" | "model_message" | "idle";
190
+ type ReceivedMessage = {
191
+ content: string;
192
+ input: InferenceInput;
193
+ };
194
+ interface FunctionCallExecutionOutput {
195
+ item: FunctionCallOutputItem;
196
+ }
197
+ interface ModelMessageParams {
198
+ answer: ModelMessageItem;
199
+ }
200
+ interface LoopStateContract {
201
+ context_update: {
202
+ input: ReceivedMessage;
203
+ output: InferenceInput;
204
+ };
205
+ inference: {
206
+ input: InferenceInput;
207
+ output: InferenceOutput;
208
+ };
209
+ inference_streaming: {
210
+ input: InferenceInput;
211
+ output: InferenceOutput;
212
+ };
213
+ function_call: {
214
+ input: FunctionCallParams;
215
+ output: FunctionCallExecutionOutput;
216
+ };
217
+ model_message: {
218
+ input: ModelMessageParams;
219
+ output: void;
220
+ };
221
+ interception: {
222
+ input: InterceptionParams;
223
+ output: InterceptionOutput;
224
+ };
225
+ idle: {
226
+ input: undefined;
227
+ output: void;
228
+ };
229
+ }
230
+ type InterceptionOutput = {
231
+ type: "continue";
232
+ transition: LoopTransition;
233
+ } | {
234
+ type: "pause";
235
+ pendingTransition: LoopTransition;
236
+ } | {
237
+ type: "stop";
238
+ reason?: string;
239
+ };
240
+ interface InterceptionParams {
241
+ pendingTransition: LoopTransition;
242
+ }
243
+ type LoopTransition<TStateId extends LoopStateId = LoopStateId> = {
244
+ [K in TStateId]: {
245
+ nextStateId: K;
246
+ input: LoopStateContract[K]["input"];
247
+ };
248
+ }[TStateId];
144
249
 
145
250
  type InferenceInput = {
146
251
  model: string;
@@ -299,46 +404,6 @@ declare class SystemMessageItem extends ContextItem {
299
404
  }): SystemMessageItem;
300
405
  }
301
406
 
302
- type SituationContext$1<TEvent extends SemanticEvent = SemanticEvent> = {
303
- readonly event: TEvent;
304
- readonly participant: Participant;
305
- };
306
- declare abstract class SituationSpecification<TEvent extends SemanticEvent = SemanticEvent> {
307
- abstract isSatisfiedBy(situationContext: SituationContext$1<TEvent>): boolean;
308
- and(other: SituationSpecification<TEvent>): SituationSpecification<TEvent>;
309
- or(other: SituationSpecification<TEvent>): SituationSpecification<TEvent>;
310
- not(): SituationSpecification<TEvent>;
311
- }
312
-
313
- interface SituationHandler {
314
- readonly specification: SituationSpecification;
315
- readonly processor: SituationProcessor;
316
- }
317
- type SituationContext<TEvent extends SemanticEvent = SemanticEvent> = {
318
- readonly event: TEvent;
319
- readonly participant: Participant;
320
- };
321
- interface SituationProcessor {
322
- apply(context: SituationContext): void | Promise<void>;
323
- }
324
-
325
- type ParticipantRole = "agent" | "human";
326
- type ParticipantManifest = {
327
- readonly id: string;
328
- readonly name: string;
329
- readonly role: ParticipantRole;
330
- readonly capabilities?: readonly string[];
331
- };
332
- declare abstract class Participant {
333
- private readonly manifest;
334
- private handlers;
335
- protected constructor(manifest: ParticipantManifest, handlers: SituationHandler[]);
336
- getManifest(): ParticipantManifest;
337
- getId(): string;
338
- getHandlers(): SituationHandler[];
339
- setHandlers(handlers: SituationHandler[]): void;
340
- }
341
-
342
407
  declare class Memory {
343
408
  private readonly context;
344
409
  private constructor();
@@ -394,6 +459,11 @@ declare abstract class RuntimeState {
394
459
  getParticipants(): readonly Participant[];
395
460
  }
396
461
 
462
+ interface InterceptionHandler {
463
+ isSatisfiedBy(transition: LoopTransition): boolean;
464
+ handle(transition: LoopTransition): Promise<LoopTransition>;
465
+ }
466
+
397
467
  declare class EventProcessor {
398
468
  process(event: SemanticEvent, consumer: Participant): void;
399
469
  }
@@ -427,7 +497,7 @@ declare function defineRuntime<TRuntimeState extends RuntimeState>(): {
427
497
  leave: (participant: Participant) => void;
428
498
  sendMessage: (message: string, senderId: string) => void;
429
499
  sendEvent: (event: SemanticEvent, senderId: string) => void;
430
- runLoop: (agentId: string, message: string, inferenceInput: InferenceInput) => void;
500
+ runLoop: (agentId: string, message: string, inferenceInput: InferenceInput, interceptionHandler: InterceptionHandler) => void;
431
501
  };
432
502
 
433
503
  declare const supportedModels: GenerativeModel[];
package/dist/index.js CHANGED
@@ -378,6 +378,16 @@ var SemanticEvent = class _SemanticEvent {
378
378
  return new _SemanticEvent(type, producerId, occurredAt, payload);
379
379
  }
380
380
  };
381
+ var ParticipantJoinedEvent = class extends SemanticEvent {
382
+ static init(manifest) {
383
+ return SemanticEvent.create("participant.joined", manifest.id, manifest);
384
+ }
385
+ };
386
+ var ParticipantLeftEvent = class extends SemanticEvent {
387
+ static init(manifest) {
388
+ return SemanticEvent.create("participant.left", manifest.id, manifest);
389
+ }
390
+ };
381
391
  var MessageSentEvent = class extends SemanticEvent {
382
392
  static init(producerId, message) {
383
393
  return SemanticEvent.create("message.sent", producerId, { message });
@@ -536,9 +546,11 @@ var RuntimeService = class {
536
546
  }
537
547
  join(participant) {
538
548
  this.state.addParticipant(participant);
549
+ this.publish(ParticipantJoinedEvent.init(participant.getManifest()));
539
550
  }
540
551
  leave(participant) {
541
552
  this.state.removeParticipant(participant);
553
+ this.publish(ParticipantLeftEvent.init(participant.getManifest()));
542
554
  }
543
555
  publish(event) {
544
556
  for (const participant of this.state.getParticipants()) {
@@ -602,28 +614,43 @@ function createSendMessage(resolveRuntime) {
602
614
  }
603
615
 
604
616
  // src/domain/agentic-environment/loop/agent-loop.ts
605
- var AgentLoop = class {
606
- constructor(stateExecutor, transitionResolver, loopVisitor) {
617
+ var AgentLoop = class _AgentLoop {
618
+ constructor(loopId, stateExecutor, transitionResolver, interceptionHandler) {
619
+ this.loopId = loopId;
607
620
  this.stateExecutor = stateExecutor;
608
621
  this.transitionResolver = transitionResolver;
609
- this.loopVisitor = loopVisitor;
622
+ this.interceptionHandler = interceptionHandler;
610
623
  }
611
- async run(message) {
624
+ async run(message, loopVisitor) {
612
625
  let transition = {
613
- nextStateId: "context_preparation",
626
+ nextStateId: "context_update",
614
627
  input: message
615
628
  };
616
629
  while (transition.nextStateId !== "idle") {
617
- const execution = await this.stateExecutor.execute(transition, this.loopVisitor);
618
- transition = this.transitionResolver.resolve(execution);
630
+ const isInterceptionSatisfied = this.interceptionHandler.isSatisfiedBy(transition);
631
+ if (isInterceptionSatisfied) {
632
+ loopVisitor.visitInterceptionStarted(transition);
633
+ transition = await this.interceptionHandler.handle(transition);
634
+ loopVisitor.visitInterceptionFinished(transition);
635
+ } else {
636
+ const execution = await this.stateExecutor.execute(transition, loopVisitor);
637
+ transition = this.transitionResolver.resolve(execution);
638
+ }
619
639
  }
620
640
  }
641
+ getLoopId() {
642
+ return this.loopId;
643
+ }
644
+ static create(stateExecutor, transitionResolver, interceptionHandler) {
645
+ const loopId = crypto.randomUUID();
646
+ return new _AgentLoop(loopId, stateExecutor, transitionResolver, interceptionHandler);
647
+ }
621
648
  };
622
649
 
623
650
  // src/domain/agentic-environment/loop/state-executor.ts
624
651
  var LoopStateExecutor = class {
625
- constructor(contextPreparationState, inferenceState, inferenceStreamingState, functionCallState, modelMessageState) {
626
- this.contextPreparationState = contextPreparationState;
652
+ constructor(contextUpdateState, inferenceState, inferenceStreamingState, functionCallState, modelMessageState) {
653
+ this.contextUpdateState = contextUpdateState;
627
654
  this.inferenceState = inferenceState;
628
655
  this.inferenceStreamingState = inferenceStreamingState;
629
656
  this.functionCallState = functionCallState;
@@ -631,8 +658,8 @@ var LoopStateExecutor = class {
631
658
  }
632
659
  async execute(transition, loopVisitor) {
633
660
  switch (transition.nextStateId) {
634
- case "context_preparation":
635
- return await this.contextPreparationState.run(transition.input, loopVisitor);
661
+ case "context_update":
662
+ return await this.contextUpdateState.run(transition.input, loopVisitor);
636
663
  case "inference":
637
664
  return await this.inferenceState.run(transition.input, loopVisitor);
638
665
  case "inference_streaming":
@@ -677,19 +704,19 @@ var FunctionCallState = class {
677
704
  }
678
705
  };
679
706
 
680
- // src/application/states/context-preparation.ts
681
- var ContextPreparationState = class {
707
+ // src/application/states/context-update.ts
708
+ var ContextUpdateState = class {
682
709
  constructor() {
683
- this.id = "context_preparation";
710
+ this.id = "context_update";
684
711
  }
685
712
  async run(input, loopVisitor) {
686
- loopVisitor.visitContextPreparationStarted(input);
713
+ loopVisitor.visitContextUpdateStarted(input);
687
714
  const userMessage = UserMessageItem.create(input.content);
688
715
  const output = {
689
716
  ...input.input,
690
717
  context: input.input.context.addContextItems([userMessage])
691
718
  };
692
- loopVisitor.visitContextPreparationCompleted(output);
719
+ loopVisitor.visitContextUpdateCompleted(output);
693
720
  return {
694
721
  stateId: this.id,
695
722
  input,
@@ -730,7 +757,7 @@ var TransitionResolver = class {
730
757
  // src/domain/agentic-environment/loop/transition-specification.ts
731
758
  var MessageReceivedSpecification = class {
732
759
  isSatisfiedBy(execution) {
733
- return execution.stateId === "context_preparation";
760
+ return execution.stateId === "context_update";
734
761
  }
735
762
  };
736
763
  function isInferenceExecution(execution) {
@@ -763,7 +790,7 @@ var ContextPreparationToInferenceRule = class {
763
790
  this.specification = new MessageReceivedSpecification();
764
791
  }
765
792
  createTransition(execution) {
766
- if (execution.stateId !== "context_preparation") {
793
+ if (execution.stateId !== "context_update") {
767
794
  throw new Error("Expected context_preparation execution");
768
795
  }
769
796
  const nextStateId = execution.output.streaming ? "inference_streaming" : "inference";
@@ -851,15 +878,16 @@ var ModelMessageToIdleRule = class {
851
878
 
852
879
  // src/domain/agentic-environment/loop/event-publisher-visitor.ts
853
880
  var EventPublisherLoopVisitor = class {
854
- constructor(agentId, runtime) {
881
+ constructor(agentId, loopId, runtime) {
855
882
  this.agentId = agentId;
883
+ this.loopId = loopId;
856
884
  this.runtime = runtime;
857
885
  }
858
- visitContextPreparationStarted(input) {
859
- this.publish("context_preparation.started", input);
886
+ visitContextUpdateStarted(input) {
887
+ this.publish("context_update.started", { ...input, loopId: this.loopId });
860
888
  }
861
- visitContextPreparationCompleted(output) {
862
- this.publish("context_preparation.completed", output);
889
+ visitContextUpdateCompleted(output) {
890
+ this.publish("context_update.completed", { ...output, loopId: this.loopId });
863
891
  }
864
892
  visitInferenceStarted(input) {
865
893
  this.publish("inference.started", input);
@@ -879,12 +907,18 @@ var EventPublisherLoopVisitor = class {
879
907
  visitModelAnswer(input) {
880
908
  this.publish("model.answer", input);
881
909
  }
910
+ visitInterceptionStarted(transition) {
911
+ this.publish("interception.started", transition);
912
+ }
913
+ visitInterceptionFinished(transition) {
914
+ this.publish("interception.finished", transition);
915
+ }
882
916
  publish(type, payload) {
883
917
  this.runtime.publish({
884
918
  type,
885
919
  producerId: this.agentId,
886
920
  occurredAt: /* @__PURE__ */ new Date(),
887
- payload
921
+ payload: { ...payload, loopId: this.loopId }
888
922
  });
889
923
  }
890
924
  };
@@ -918,7 +952,7 @@ var InferenceStreamingState = class {
918
952
 
919
953
  // src/application/use-cases/run-loop.ts
920
954
  function createRunLoop(resolveRuntime) {
921
- return function runLoop(agentId, message, inferenceInput) {
955
+ return function runLoop(agentId, message, inferenceInput, interceptionHandler) {
922
956
  const runtime = resolveRuntime();
923
957
  const inferenceRunner = runtime.getInferenceRunner();
924
958
  const functionCallRunner = runtime.getFunctionCallRunner();
@@ -931,21 +965,21 @@ function createRunLoop(resolveRuntime) {
931
965
  new ModelMessageToIdleRule()
932
966
  ]);
933
967
  const stateExecutor = new LoopStateExecutor(
934
- new ContextPreparationState(),
968
+ new ContextUpdateState(),
935
969
  new InferenceState(inferenceRunner),
936
970
  new InferenceStreamingState(inferenceRunner),
937
971
  new FunctionCallState(functionCallRunner),
938
972
  new ModelMessageState()
939
973
  );
940
- const agentLoop = new AgentLoop(
941
- stateExecutor,
942
- transitionResolver,
943
- new EventPublisherLoopVisitor(agentId, runtime)
974
+ const agentLoop = AgentLoop.create(stateExecutor, transitionResolver, interceptionHandler);
975
+ const loopVisitor = new EventPublisherLoopVisitor(agentId, agentLoop.getLoopId(), runtime);
976
+ agentLoop.run(
977
+ {
978
+ content: message,
979
+ input: inferenceInput
980
+ },
981
+ loopVisitor
944
982
  );
945
- agentLoop.run({
946
- content: message,
947
- input: inferenceInput
948
- });
949
983
  };
950
984
  }
951
985