@moltium/world-core 0.1.18 → 0.1.20

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.js CHANGED
@@ -113,7 +113,21 @@ var WorldConfigSchema = z.object({
113
113
  blockchain: BlockchainConfigSchema.optional(),
114
114
  token: TokenConfigSchema.optional(),
115
115
  rules: z.array(z.any()).optional(),
116
- agentUrls: z.array(z.string().url()).optional()
116
+ agentUrls: z.array(z.string().url()).optional(),
117
+ actions: z.array(z.object({
118
+ name: z.string().min(1),
119
+ description: z.string(),
120
+ parameters: z.record(z.object({
121
+ type: z.enum(["string", "number", "boolean", "object"]),
122
+ required: z.boolean().optional(),
123
+ description: z.string().optional()
124
+ })).optional()
125
+ })).optional(),
126
+ orchestration: z.object({
127
+ broadcastOnTick: z.boolean().optional(),
128
+ tickTimeout: z.number().int().positive().optional(),
129
+ promptTemplate: z.string().optional()
130
+ }).optional()
117
131
  });
118
132
  function validateWorldConfig(config) {
119
133
  try {
@@ -413,7 +427,7 @@ async function createLevelDBAdapter(config) {
413
427
  }
414
428
 
415
429
  // src/engine/World.ts
416
- import { v4 as uuidv4 } from "uuid";
430
+ import { v4 as uuidv43 } from "uuid";
417
431
 
418
432
  // src/discovery/AgentEvaluator.ts
419
433
  var logger2 = createLogger("AgentEvaluator");
@@ -768,8 +782,538 @@ var BlockchainClient = class {
768
782
  }
769
783
  };
770
784
 
785
+ // src/a2a/WorldA2AClient.ts
786
+ import { A2AClient } from "@moltium/core";
787
+ var logger4 = createLogger("WorldA2AClient");
788
+ var WorldA2AClient = class {
789
+ clients = /* @__PURE__ */ new Map();
790
+ /**
791
+ * Add an agent to the client pool
792
+ */
793
+ addAgent(agentUrl) {
794
+ if (this.clients.has(agentUrl)) {
795
+ logger4.debug(`Agent already in client pool: ${agentUrl}`);
796
+ return;
797
+ }
798
+ const client = new A2AClient({ agentUrl });
799
+ this.clients.set(agentUrl, client);
800
+ logger4.info(`Added agent to A2A client pool: ${agentUrl}`);
801
+ }
802
+ /**
803
+ * Remove an agent from the client pool
804
+ */
805
+ removeAgent(agentUrl) {
806
+ this.clients.delete(agentUrl);
807
+ logger4.info(`Removed agent from A2A client pool: ${agentUrl}`);
808
+ }
809
+ /**
810
+ * Send an A2A message to a specific agent
811
+ */
812
+ async sendToAgent(agentUrl, message, metadata) {
813
+ const client = this.clients.get(agentUrl);
814
+ if (!client) {
815
+ return {
816
+ success: false,
817
+ error: `Agent not in client pool: ${agentUrl}`,
818
+ agentUrl
819
+ };
820
+ }
821
+ try {
822
+ const response = await client.sendMessage({ text: message, metadata });
823
+ logger4.debug(`A2A message sent to ${agentUrl}`, { success: response.success });
824
+ return response;
825
+ } catch (error) {
826
+ logger4.error(`Failed to send A2A message to ${agentUrl}:`, error);
827
+ return {
828
+ success: false,
829
+ error: error?.message || String(error),
830
+ agentUrl
831
+ };
832
+ }
833
+ }
834
+ /**
835
+ * Broadcast an A2A message to all agents in the pool
836
+ */
837
+ async broadcastToAll(message, metadata) {
838
+ const results = /* @__PURE__ */ new Map();
839
+ const promises = Array.from(this.clients.entries()).map(
840
+ async ([agentUrl]) => {
841
+ const response = await this.sendToAgent(agentUrl, message, metadata);
842
+ results.set(agentUrl, response);
843
+ }
844
+ );
845
+ await Promise.allSettled(promises);
846
+ logger4.info(`Broadcast complete: ${results.size} agents`, {
847
+ succeeded: Array.from(results.values()).filter((r) => r.success).length,
848
+ failed: Array.from(results.values()).filter((r) => !r.success).length
849
+ });
850
+ return results;
851
+ }
852
+ /**
853
+ * Get the number of agents in the pool
854
+ */
855
+ get size() {
856
+ return this.clients.size;
857
+ }
858
+ /**
859
+ * Check if an agent is in the pool
860
+ */
861
+ has(agentUrl) {
862
+ return this.clients.has(agentUrl);
863
+ }
864
+ /**
865
+ * Get all agent URLs in the pool
866
+ */
867
+ getAgentUrls() {
868
+ return Array.from(this.clients.keys());
869
+ }
870
+ };
871
+
872
+ // src/engine/WorldActions.ts
873
+ var logger5 = createLogger("WorldActions");
874
+ var WorldActionsRegistry = class {
875
+ actions = /* @__PURE__ */ new Map();
876
+ /**
877
+ * Register a world action
878
+ */
879
+ register(action) {
880
+ if (this.actions.has(action.name)) {
881
+ logger5.warn(`Overwriting existing action: ${action.name}`);
882
+ }
883
+ this.actions.set(action.name, action);
884
+ logger5.debug(`Registered world action: ${action.name}`);
885
+ }
886
+ /**
887
+ * Register multiple actions at once
888
+ */
889
+ registerAll(actions) {
890
+ for (const action of actions) {
891
+ this.register(action);
892
+ }
893
+ }
894
+ /**
895
+ * Get all registered actions
896
+ */
897
+ getAll() {
898
+ return Array.from(this.actions.values());
899
+ }
900
+ /**
901
+ * Get a specific action by name
902
+ */
903
+ get(name) {
904
+ return this.actions.get(name);
905
+ }
906
+ /**
907
+ * Check if an action exists
908
+ */
909
+ has(name) {
910
+ return this.actions.has(name);
911
+ }
912
+ /**
913
+ * Validate an action name and its parameters
914
+ */
915
+ validate(actionName, params) {
916
+ const action = this.actions.get(actionName);
917
+ if (!action) {
918
+ return { valid: false, error: `Unknown action: ${actionName}` };
919
+ }
920
+ if (!action.parameters) {
921
+ return { valid: true };
922
+ }
923
+ for (const [paramName, paramDef] of Object.entries(action.parameters)) {
924
+ if (paramDef.required && !(paramName in params)) {
925
+ return {
926
+ valid: false,
927
+ error: `Missing required parameter: ${paramName} for action ${actionName}`
928
+ };
929
+ }
930
+ if (paramName in params && params[paramName] !== void 0) {
931
+ const actualType = typeof params[paramName];
932
+ if (paramDef.type === "object") {
933
+ if (actualType !== "object" || params[paramName] === null) {
934
+ return {
935
+ valid: false,
936
+ error: `Parameter ${paramName} must be an object`
937
+ };
938
+ }
939
+ } else if (actualType !== paramDef.type) {
940
+ return {
941
+ valid: false,
942
+ error: `Parameter ${paramName} must be of type ${paramDef.type}, got ${actualType}`
943
+ };
944
+ }
945
+ }
946
+ }
947
+ return { valid: true };
948
+ }
949
+ /**
950
+ * Get action names as a simple list (for tick context)
951
+ */
952
+ getActionNames() {
953
+ return Array.from(this.actions.keys());
954
+ }
955
+ /**
956
+ * Get actions as a serializable summary (for tick context)
957
+ */
958
+ toSummary() {
959
+ return this.getAll().map((a) => ({
960
+ name: a.name,
961
+ description: a.description,
962
+ ...a.parameters && { parameters: a.parameters }
963
+ }));
964
+ }
965
+ };
966
+
967
+ // src/engine/ActionProcessor.ts
968
+ import { v4 as uuidv4 } from "uuid";
969
+ var logger6 = createLogger("ActionProcessor");
970
+ var ActionProcessor = class {
971
+ constructor(rules, actionsRegistry) {
972
+ this.rules = rules;
973
+ this.actionsRegistry = actionsRegistry;
974
+ }
975
+ /**
976
+ * Process an agent's tick response: validate action and check rules
977
+ */
978
+ async process(response, agent, worldContext) {
979
+ const violations = [];
980
+ const events = [];
981
+ if (response.error || !response.action) {
982
+ return { accepted: false, violations: [], events: [] };
983
+ }
984
+ const actionValidation = this.actionsRegistry.validate(
985
+ response.action,
986
+ response.parameters || {}
987
+ );
988
+ if (!actionValidation.valid) {
989
+ logger6.warn(`Invalid action from ${response.agentUrl}: ${actionValidation.error}`);
990
+ violations.push({
991
+ ruleId: "_action_validation",
992
+ severity: "warning",
993
+ message: actionValidation.error,
994
+ agentUrl: response.agentUrl,
995
+ action: "warn"
996
+ });
997
+ return { accepted: false, violations, events: [] };
998
+ }
999
+ const ruleContext = {
1000
+ world: {
1001
+ phase: worldContext.phase,
1002
+ tick: worldContext.tick,
1003
+ agents: worldContext.agents
1004
+ },
1005
+ event: {
1006
+ id: uuidv4(),
1007
+ type: "agent_action",
1008
+ timestamp: Date.now(),
1009
+ agentUrl: response.agentUrl,
1010
+ data: {
1011
+ action: response.action,
1012
+ parameters: response.parameters
1013
+ }
1014
+ },
1015
+ agent
1016
+ };
1017
+ for (const rule of this.rules) {
1018
+ try {
1019
+ const violation = await rule.evaluate(ruleContext);
1020
+ if (violation) {
1021
+ violations.push(violation);
1022
+ logger6.warn(`Rule violation: ${rule.name}`, {
1023
+ agentUrl: response.agentUrl,
1024
+ action: response.action,
1025
+ severity: violation.severity
1026
+ });
1027
+ }
1028
+ } catch (error) {
1029
+ logger6.error(`Rule evaluation error (${rule.name}):`, error);
1030
+ }
1031
+ }
1032
+ const blocking = violations.filter(
1033
+ (v) => v.severity === "error" || v.severity === "critical"
1034
+ );
1035
+ if (blocking.length > 0) {
1036
+ return { accepted: false, violations, events: [] };
1037
+ }
1038
+ events.push({
1039
+ id: uuidv4(),
1040
+ type: "action_executed",
1041
+ timestamp: Date.now(),
1042
+ agentUrl: response.agentUrl,
1043
+ data: {
1044
+ action: response.action,
1045
+ parameters: response.parameters
1046
+ }
1047
+ });
1048
+ return {
1049
+ accepted: true,
1050
+ violations,
1051
+ stateUpdates: {
1052
+ [`lastAction_${response.agentUrl}`]: {
1053
+ action: response.action,
1054
+ parameters: response.parameters,
1055
+ tick: worldContext.tick
1056
+ }
1057
+ },
1058
+ events
1059
+ };
1060
+ }
1061
+ /**
1062
+ * Update the rules list
1063
+ */
1064
+ setRules(rules) {
1065
+ this.rules = rules;
1066
+ }
1067
+ };
1068
+
1069
+ // src/engine/TickOrchestrator.ts
1070
+ import { v4 as uuidv42 } from "uuid";
1071
+ var logger7 = createLogger("TickOrchestrator");
1072
+ var TickOrchestrator = class {
1073
+ constructor(a2aClient, actionsRegistry, rules, config) {
1074
+ this.a2aClient = a2aClient;
1075
+ this.actionsRegistry = actionsRegistry;
1076
+ this.actionProcessor = new ActionProcessor(rules, actionsRegistry);
1077
+ this.orchestrationConfig = {
1078
+ broadcastOnTick: config?.broadcastOnTick ?? true,
1079
+ tickTimeout: config?.tickTimeout ?? 1e4,
1080
+ promptTemplate: config?.promptTemplate
1081
+ };
1082
+ }
1083
+ actionProcessor;
1084
+ orchestrationConfig;
1085
+ /**
1086
+ * Execute a single world tick
1087
+ */
1088
+ async executeTick(tick, agents, state, worldName) {
1089
+ const result = {
1090
+ tick,
1091
+ responses: /* @__PURE__ */ new Map(),
1092
+ events: [],
1093
+ stateUpdates: {},
1094
+ errors: []
1095
+ };
1096
+ if (agents.length === 0 || !this.orchestrationConfig.broadcastOnTick) {
1097
+ logger7.debug(`Tick ${tick}: no agents to broadcast to`);
1098
+ return result;
1099
+ }
1100
+ const tickContext = this.buildTickContext(tick, agents, state, worldName);
1101
+ const message = JSON.stringify(tickContext);
1102
+ logger7.debug(`Tick ${tick}: broadcasting to ${agents.length} agents`);
1103
+ const responses = await this.a2aClient.broadcastToAll(message, {
1104
+ type: "world_tick",
1105
+ tick,
1106
+ worldName
1107
+ });
1108
+ const agentsMap = /* @__PURE__ */ new Map();
1109
+ for (const agent of agents) {
1110
+ agentsMap.set(agent.url, agent);
1111
+ }
1112
+ for (const [agentUrl, a2aResponse] of responses) {
1113
+ const tickResponse = this.parseAgentResponse(agentUrl, a2aResponse);
1114
+ result.responses.set(agentUrl, tickResponse);
1115
+ if (tickResponse.error) {
1116
+ result.errors.push({ agentUrl, error: tickResponse.error });
1117
+ continue;
1118
+ }
1119
+ const agent = agentsMap.get(agentUrl);
1120
+ if (!agent || !tickResponse.action) continue;
1121
+ const processResult = await this.actionProcessor.process(
1122
+ tickResponse,
1123
+ agent,
1124
+ { phase: state.phase, tick, agents: agentsMap }
1125
+ );
1126
+ if (processResult.accepted) {
1127
+ if (processResult.stateUpdates) {
1128
+ Object.assign(result.stateUpdates, processResult.stateUpdates);
1129
+ }
1130
+ if (processResult.events) {
1131
+ result.events.push(...processResult.events);
1132
+ }
1133
+ }
1134
+ for (const violation of processResult.violations) {
1135
+ result.events.push({
1136
+ id: uuidv42(),
1137
+ type: "rule_violation",
1138
+ timestamp: Date.now(),
1139
+ agentUrl,
1140
+ data: {
1141
+ ruleId: violation.ruleId,
1142
+ severity: violation.severity,
1143
+ message: violation.message
1144
+ }
1145
+ });
1146
+ }
1147
+ }
1148
+ result.events.push({
1149
+ id: uuidv42(),
1150
+ type: "tick",
1151
+ timestamp: Date.now(),
1152
+ data: {
1153
+ tick,
1154
+ agentsBroadcasted: agents.length,
1155
+ responsesReceived: result.responses.size,
1156
+ errorsCount: result.errors.length
1157
+ }
1158
+ });
1159
+ logger7.info(`Tick ${tick} complete`, {
1160
+ responses: result.responses.size,
1161
+ errors: result.errors.length,
1162
+ stateUpdates: Object.keys(result.stateUpdates).length
1163
+ });
1164
+ return result;
1165
+ }
1166
+ /**
1167
+ * Build the tick context that gets sent to each agent
1168
+ */
1169
+ buildTickContext(tick, agents, state, worldName) {
1170
+ const availableActions = this.actionsRegistry.toSummary();
1171
+ const agentsSummary = agents.map((a) => ({
1172
+ name: a.name,
1173
+ role: a.role || "participant",
1174
+ skills: a.skills.map((s) => s.id)
1175
+ }));
1176
+ const prompt = this.orchestrationConfig.promptTemplate || `You are participating in world "${worldName}". Current tick: ${tick}. Choose an action from the available actions and respond with a JSON object: { "action": "<action_name>", "parameters": { ... } }. You may also include a "message" field for free-form communication.`;
1177
+ return {
1178
+ type: "world_tick",
1179
+ tick,
1180
+ worldName,
1181
+ state: {
1182
+ phase: state.phase,
1183
+ tick: state.tick,
1184
+ round: state.round,
1185
+ metadata: state.metadata
1186
+ },
1187
+ availableActions,
1188
+ agents: agentsSummary,
1189
+ prompt
1190
+ };
1191
+ }
1192
+ /**
1193
+ * Parse an A2A response into an AgentTickResponse
1194
+ */
1195
+ parseAgentResponse(agentUrl, a2aResponse) {
1196
+ if (!a2aResponse.success) {
1197
+ return {
1198
+ agentUrl,
1199
+ error: a2aResponse.error || "A2A communication failed"
1200
+ };
1201
+ }
1202
+ const reply = a2aResponse.reply;
1203
+ if (!reply) {
1204
+ return { agentUrl, message: "" };
1205
+ }
1206
+ try {
1207
+ const parsed = JSON.parse(reply);
1208
+ return {
1209
+ agentUrl,
1210
+ action: parsed.action,
1211
+ parameters: parsed.parameters || {},
1212
+ message: parsed.message
1213
+ };
1214
+ } catch {
1215
+ return {
1216
+ agentUrl,
1217
+ message: reply
1218
+ };
1219
+ }
1220
+ }
1221
+ /**
1222
+ * Update orchestration config
1223
+ */
1224
+ setConfig(config) {
1225
+ Object.assign(this.orchestrationConfig, config);
1226
+ }
1227
+ /**
1228
+ * Update rules on the action processor
1229
+ */
1230
+ setRules(rules) {
1231
+ this.actionProcessor.setRules(rules);
1232
+ }
1233
+ };
1234
+
1235
+ // src/a2a/MessageRouter.ts
1236
+ var logger8 = createLogger("MessageRouter");
1237
+ var MessageRouter = class {
1238
+ constructor(a2aClient, getAgents) {
1239
+ this.a2aClient = a2aClient;
1240
+ this.getAgents = getAgents;
1241
+ }
1242
+ /**
1243
+ * Route a message from one agent to another
1244
+ */
1245
+ async route(fromAgentUrl, toAgentUrl, message) {
1246
+ const agents = this.getAgents();
1247
+ const sender = agents.find((a) => a.url === fromAgentUrl);
1248
+ if (!sender) {
1249
+ return {
1250
+ success: false,
1251
+ error: `Sender not in world: ${fromAgentUrl}`
1252
+ };
1253
+ }
1254
+ const recipient = agents.find((a) => a.url === toAgentUrl);
1255
+ if (!recipient) {
1256
+ return {
1257
+ success: false,
1258
+ error: `Recipient not in world: ${toAgentUrl}`
1259
+ };
1260
+ }
1261
+ const wrappedMessage = JSON.stringify({
1262
+ type: "world_message",
1263
+ from: {
1264
+ url: sender.url,
1265
+ name: sender.name,
1266
+ role: sender.role
1267
+ },
1268
+ message
1269
+ });
1270
+ logger8.info(`Routing message: ${sender.name} \u2192 ${recipient.name}`);
1271
+ return this.a2aClient.sendToAgent(toAgentUrl, wrappedMessage, {
1272
+ type: "world_message",
1273
+ fromAgentUrl
1274
+ });
1275
+ }
1276
+ /**
1277
+ * Broadcast a message from one agent to all other agents in the world
1278
+ */
1279
+ async routeToAll(fromAgentUrl, message) {
1280
+ const agents = this.getAgents();
1281
+ const sender = agents.find((a) => a.url === fromAgentUrl);
1282
+ if (!sender) {
1283
+ const result = /* @__PURE__ */ new Map();
1284
+ result.set(fromAgentUrl, {
1285
+ success: false,
1286
+ error: `Sender not in world: ${fromAgentUrl}`
1287
+ });
1288
+ return result;
1289
+ }
1290
+ const wrappedMessage = JSON.stringify({
1291
+ type: "world_broadcast",
1292
+ from: {
1293
+ url: sender.url,
1294
+ name: sender.name,
1295
+ role: sender.role
1296
+ },
1297
+ message
1298
+ });
1299
+ const results = /* @__PURE__ */ new Map();
1300
+ const recipients = agents.filter((a) => a.url !== fromAgentUrl);
1301
+ const promises = recipients.map(async (recipient) => {
1302
+ const response = await this.a2aClient.sendToAgent(
1303
+ recipient.url,
1304
+ wrappedMessage,
1305
+ { type: "world_broadcast", fromAgentUrl }
1306
+ );
1307
+ results.set(recipient.url, response);
1308
+ });
1309
+ await Promise.allSettled(promises);
1310
+ logger8.info(`Broadcast from ${sender.name} to ${recipients.length} agents`);
1311
+ return results;
1312
+ }
1313
+ };
1314
+
771
1315
  // src/engine/World.ts
772
- var logger4 = createLogger("World");
1316
+ var logger9 = createLogger("World");
773
1317
  var World = class {
774
1318
  constructor(config) {
775
1319
  this.config = config;
@@ -784,9 +1328,26 @@ var World = class {
784
1328
  this.agents = /* @__PURE__ */ new Map();
785
1329
  this.cardFetcher = new CardFetcher();
786
1330
  this.evaluator = new AgentEvaluator(config.admission);
787
- logger4.info(`World "${config.name}" created`, {
1331
+ this.a2aClient = new WorldA2AClient();
1332
+ this.actionsRegistry = new WorldActionsRegistry();
1333
+ this.orchestrator = new TickOrchestrator(
1334
+ this.a2aClient,
1335
+ this.actionsRegistry,
1336
+ config.rules || [],
1337
+ config.orchestration
1338
+ );
1339
+ this.messageRouter = new MessageRouter(
1340
+ this.a2aClient,
1341
+ () => this.getAgents()
1342
+ );
1343
+ if (config.actions && config.actions.length > 0) {
1344
+ this.actionsRegistry.registerAll(config.actions);
1345
+ logger9.info(`Registered ${config.actions.length} world actions`);
1346
+ }
1347
+ logger9.info(`World "${config.name}" created`, {
788
1348
  type: config.type || "generic",
789
- maxAgents: config.admission.maxAgents
1349
+ maxAgents: config.admission.maxAgents,
1350
+ orchestration: !!config.orchestration?.broadcastOnTick
790
1351
  });
791
1352
  }
792
1353
  state;
@@ -797,21 +1358,26 @@ var World = class {
797
1358
  evaluator;
798
1359
  tickInterval = null;
799
1360
  autoSaveInterval = null;
1361
+ // Agent-World bridge components
1362
+ a2aClient;
1363
+ actionsRegistry;
1364
+ orchestrator;
1365
+ messageRouter;
800
1366
  /**
801
1367
  * Initialize the world (connect persistence, restore state, discover agents)
802
1368
  */
803
1369
  async init() {
804
- logger4.info("Initializing world...");
1370
+ logger9.info("Initializing world...");
805
1371
  this.setState("initializing");
806
1372
  try {
807
1373
  if (this.config.persistence) {
808
- logger4.info(`Connecting to persistence backend: ${this.config.persistence.type}`);
1374
+ logger9.info(`Connecting to persistence backend: ${this.config.persistence.type}`);
809
1375
  this.persistence = await createPersistence(this.config.persistence);
810
1376
  await this.persistence.connect();
811
1377
  const savedState = await this.persistence.loadState();
812
1378
  if (savedState) {
813
1379
  this.state = savedState;
814
- logger4.info("Restored world state from persistence", {
1380
+ logger9.info("Restored world state from persistence", {
815
1381
  phase: savedState.phase,
816
1382
  tick: savedState.tick
817
1383
  });
@@ -819,16 +1385,16 @@ var World = class {
819
1385
  for (const agent of savedAgents) {
820
1386
  this.agents.set(agent.url, agent);
821
1387
  }
822
- logger4.info(`Restored ${savedAgents.length} agents from persistence`);
1388
+ logger9.info(`Restored ${savedAgents.length} agents from persistence`);
823
1389
  }
824
1390
  }
825
1391
  if (this.config.blockchain) {
826
- logger4.info("Initializing blockchain client...");
1392
+ logger9.info("Initializing blockchain client...");
827
1393
  this.blockchainClient = new BlockchainClient(this.config.blockchain);
828
1394
  await this.blockchainClient.init();
829
1395
  }
830
1396
  if (this.config.agentUrls && this.config.agentUrls.length > 0) {
831
- logger4.info(`Discovering ${this.config.agentUrls.length} pre-configured agents...`);
1397
+ logger9.info(`Discovering ${this.config.agentUrls.length} pre-configured agents...`);
832
1398
  const results = await this.cardFetcher.fetchCards(this.config.agentUrls);
833
1399
  for (let i = 0; i < results.length; i++) {
834
1400
  const result = results[i];
@@ -836,7 +1402,7 @@ var World = class {
836
1402
  try {
837
1403
  await this.admitAgent(result.card);
838
1404
  } catch (error) {
839
- logger4.warn(`Failed to admit pre-configured agent:`, error.message);
1405
+ logger9.warn(`Failed to admit pre-configured agent:`, error.message);
840
1406
  }
841
1407
  }
842
1408
  }
@@ -845,12 +1411,12 @@ var World = class {
845
1411
  this.startAutoSave();
846
1412
  }
847
1413
  this.setState("ready");
848
- logger4.info("World initialized successfully", {
1414
+ logger9.info("World initialized successfully", {
849
1415
  agents: this.agents.size,
850
1416
  persistence: this.config.persistence?.type || "none"
851
1417
  });
852
1418
  } catch (error) {
853
- logger4.error("Failed to initialize world:", error);
1419
+ logger9.error("Failed to initialize world:", error);
854
1420
  this.setState("failed");
855
1421
  throw error;
856
1422
  }
@@ -860,13 +1426,13 @@ var World = class {
860
1426
  */
861
1427
  async start() {
862
1428
  if (this.state.phase === "running") {
863
- logger4.warn("World is already running");
1429
+ logger9.warn("World is already running");
864
1430
  return;
865
1431
  }
866
- logger4.info("Starting world simulation...");
1432
+ logger9.info("Starting world simulation...");
867
1433
  this.setState("running");
868
1434
  await this.logEvent({
869
- id: uuidv4(),
1435
+ id: uuidv43(),
870
1436
  type: "world_started",
871
1437
  timestamp: Date.now()
872
1438
  });
@@ -878,7 +1444,7 @@ var World = class {
878
1444
  * Stop the world simulation
879
1445
  */
880
1446
  async stop() {
881
- logger4.info("Stopping world...");
1447
+ logger9.info("Stopping world...");
882
1448
  this.setState("stopped");
883
1449
  if (this.tickInterval) {
884
1450
  clearInterval(this.tickInterval);
@@ -892,11 +1458,11 @@ var World = class {
892
1458
  await this.persistence.saveState(this.state);
893
1459
  }
894
1460
  await this.logEvent({
895
- id: uuidv4(),
1461
+ id: uuidv43(),
896
1462
  type: "world_stopped",
897
1463
  timestamp: Date.now()
898
1464
  });
899
- logger4.info("World stopped");
1465
+ logger9.info("World stopped");
900
1466
  }
901
1467
  /**
902
1468
  * Admit an agent to the world
@@ -911,15 +1477,15 @@ var World = class {
911
1477
  if (!isValid) {
912
1478
  throw new Error("Agent not registered in on-chain AgentRegistry");
913
1479
  }
914
- logger4.info(`Agent validated on-chain: ${card.name}`);
1480
+ logger9.info(`Agent validated on-chain: ${card.name}`);
915
1481
  }
916
1482
  if (this.blockchainClient && this.config.blockchain?.requireMembership && walletAddress) {
917
1483
  const hasMembership = await this.blockchainClient.hasMembership(walletAddress);
918
1484
  if (!hasMembership) {
919
- logger4.info(`Minting membership NFT for agent: ${card.name}`);
1485
+ logger9.info(`Minting membership NFT for agent: ${card.name}`);
920
1486
  await this.blockchainClient.mintMembership(walletAddress);
921
1487
  } else {
922
- logger4.info(`Agent already has membership: ${card.name}`);
1488
+ logger9.info(`Agent already has membership: ${card.name}`);
923
1489
  }
924
1490
  }
925
1491
  const profile = {
@@ -938,17 +1504,18 @@ var World = class {
938
1504
  walletAddress
939
1505
  };
940
1506
  this.agents.set(profile.url, profile);
1507
+ this.a2aClient.addAgent(profile.url);
941
1508
  if (this.persistence) {
942
1509
  await this.persistence.saveAgent(profile);
943
1510
  }
944
1511
  await this.logEvent({
945
- id: uuidv4(),
1512
+ id: uuidv43(),
946
1513
  type: "agent_joined",
947
1514
  timestamp: Date.now(),
948
1515
  agentUrl: profile.url,
949
1516
  data: { name: profile.name, role: profile.role }
950
1517
  });
951
- logger4.info(`Agent admitted: ${profile.name}`, {
1518
+ logger9.info(`Agent admitted: ${profile.name}`, {
952
1519
  role: profile.role,
953
1520
  totalAgents: this.agents.size
954
1521
  });
@@ -962,17 +1529,18 @@ var World = class {
962
1529
  throw new Error(`Agent not found: ${agentUrl}`);
963
1530
  }
964
1531
  this.agents.delete(agentUrl);
1532
+ this.a2aClient.removeAgent(agentUrl);
965
1533
  if (this.persistence) {
966
1534
  await this.persistence.removeAgent(agentUrl);
967
1535
  }
968
1536
  await this.logEvent({
969
- id: uuidv4(),
1537
+ id: uuidv43(),
970
1538
  type: "agent_left",
971
1539
  timestamp: Date.now(),
972
1540
  agentUrl,
973
1541
  data: { name: agent.name }
974
1542
  });
975
- logger4.info(`Agent removed: ${agent.name}`, {
1543
+ logger9.info(`Agent removed: ${agent.name}`, {
976
1544
  totalAgents: this.agents.size
977
1545
  });
978
1546
  }
@@ -988,6 +1556,18 @@ var World = class {
988
1556
  getState() {
989
1557
  return { ...this.state };
990
1558
  }
1559
+ /**
1560
+ * Get the message router (for agent-to-agent communication via server)
1561
+ */
1562
+ getMessageRouter() {
1563
+ return this.messageRouter;
1564
+ }
1565
+ /**
1566
+ * Get the actions registry
1567
+ */
1568
+ getActionsRegistry() {
1569
+ return this.actionsRegistry;
1570
+ }
991
1571
  /**
992
1572
  * Log an event
993
1573
  */
@@ -1011,10 +1591,10 @@ var World = class {
1011
1591
  this.autoSaveInterval = setInterval(async () => {
1012
1592
  if (this.persistence) {
1013
1593
  await this.persistence.saveState(this.state);
1014
- logger4.debug("Auto-saved world state");
1594
+ logger9.debug("Auto-saved world state");
1015
1595
  }
1016
1596
  }, interval);
1017
- logger4.info(`Auto-save enabled (interval: ${interval}ms)`);
1597
+ logger9.info(`Auto-save enabled (interval: ${interval}ms)`);
1018
1598
  }
1019
1599
  /**
1020
1600
  * Start simulation ticking
@@ -1023,31 +1603,48 @@ var World = class {
1023
1603
  const interval = this.config.simulation.tickIntervalMs;
1024
1604
  this.tickInterval = setInterval(async () => {
1025
1605
  this.state.tick++;
1026
- await this.logEvent({
1027
- id: uuidv4(),
1028
- type: "tick",
1029
- timestamp: Date.now(),
1030
- data: { tick: this.state.tick }
1031
- });
1032
- logger4.debug(`Tick ${this.state.tick}`);
1606
+ this.state.timestamp = Date.now();
1607
+ try {
1608
+ const tickResult = await this.orchestrator.executeTick(
1609
+ this.state.tick,
1610
+ this.getAgents(),
1611
+ this.state,
1612
+ this.config.name
1613
+ );
1614
+ if (tickResult.stateUpdates && Object.keys(tickResult.stateUpdates).length > 0) {
1615
+ Object.assign(this.state.metadata, tickResult.stateUpdates);
1616
+ }
1617
+ for (const event of tickResult.events) {
1618
+ await this.logEvent(event);
1619
+ }
1620
+ } catch (error) {
1621
+ logger9.error(`Tick ${this.state.tick} orchestration error:`, error);
1622
+ await this.logEvent({
1623
+ id: uuidv43(),
1624
+ type: "tick_error",
1625
+ timestamp: Date.now(),
1626
+ data: { tick: this.state.tick, error: error?.message || String(error) }
1627
+ });
1628
+ }
1629
+ logger9.debug(`Tick ${this.state.tick}`);
1033
1630
  if (this.config.simulation?.maxTicks && this.state.tick >= this.config.simulation.maxTicks) {
1034
- logger4.info("Max ticks reached, stopping world");
1631
+ logger9.info("Max ticks reached, stopping world");
1035
1632
  await this.stop();
1036
1633
  }
1037
1634
  }, interval);
1038
- logger4.info(`Simulation ticking enabled (interval: ${interval}ms)`);
1635
+ logger9.info(`Simulation ticking enabled (interval: ${interval}ms)`);
1039
1636
  }
1040
1637
  };
1041
1638
 
1042
1639
  // src/server/app.ts
1043
1640
  import express from "express";
1044
- var logger5 = createLogger("WorldServer");
1641
+ var logger10 = createLogger("WorldServer");
1045
1642
  function createWorldApp(world) {
1046
1643
  const app = express();
1047
1644
  app.use(express.json());
1048
1645
  app.use(express.urlencoded({ extended: true }));
1049
1646
  app.use((req, res, next) => {
1050
- logger5.debug(`${req.method} ${req.path}`, {
1647
+ logger10.debug(`${req.method} ${req.path}`, {
1051
1648
  query: req.query,
1052
1649
  ip: req.ip
1053
1650
  });
@@ -1077,7 +1674,7 @@ function createWorldApp(world) {
1077
1674
  error: "agentUrl is required"
1078
1675
  });
1079
1676
  }
1080
- logger5.info(`Agent join request from: ${agentUrl}`, {
1677
+ logger10.info(`Agent join request from: ${agentUrl}`, {
1081
1678
  wallet: walletAddress || "none"
1082
1679
  });
1083
1680
  const cardFetcher = new (await import("./CardFetcher-3QKJ2I5P.js")).CardFetcher();
@@ -1098,7 +1695,7 @@ function createWorldApp(world) {
1098
1695
  }
1099
1696
  });
1100
1697
  } catch (error) {
1101
- logger5.error("Failed to process join request:", error);
1698
+ logger10.error("Failed to process join request:", error);
1102
1699
  res.status(400).json({
1103
1700
  success: false,
1104
1701
  error: error.message || "Failed to join world"
@@ -1152,6 +1749,60 @@ function createWorldApp(world) {
1152
1749
  });
1153
1750
  }
1154
1751
  });
1752
+ app.post("/world/message", async (req, res) => {
1753
+ try {
1754
+ const { fromAgentUrl, toAgentUrl, message } = req.body;
1755
+ if (!fromAgentUrl) {
1756
+ return res.status(400).json({
1757
+ success: false,
1758
+ error: "fromAgentUrl is required"
1759
+ });
1760
+ }
1761
+ if (!message) {
1762
+ return res.status(400).json({
1763
+ success: false,
1764
+ error: "message is required"
1765
+ });
1766
+ }
1767
+ const router = world.getMessageRouter();
1768
+ if (toAgentUrl) {
1769
+ const result = await router.route(fromAgentUrl, toAgentUrl, message);
1770
+ res.json({
1771
+ success: result.success,
1772
+ reply: result.reply,
1773
+ error: result.error
1774
+ });
1775
+ } else {
1776
+ const results = await router.routeToAll(fromAgentUrl, message);
1777
+ const responses = {};
1778
+ for (const [url, result] of results) {
1779
+ responses[url] = {
1780
+ success: result.success,
1781
+ reply: result.reply,
1782
+ error: result.error
1783
+ };
1784
+ }
1785
+ res.json({
1786
+ success: true,
1787
+ responses,
1788
+ count: results.size
1789
+ });
1790
+ }
1791
+ } catch (error) {
1792
+ logger10.error("Failed to route message:", error);
1793
+ res.status(500).json({
1794
+ success: false,
1795
+ error: error.message || "Failed to route message"
1796
+ });
1797
+ }
1798
+ });
1799
+ app.get("/world/actions", (req, res) => {
1800
+ const registry = world.getActionsRegistry();
1801
+ res.json({
1802
+ actions: registry.toSummary(),
1803
+ count: registry.getAll().length
1804
+ });
1805
+ });
1155
1806
  app.delete("/world/agents/:agentUrl", async (req, res) => {
1156
1807
  try {
1157
1808
  const agentUrlParam = req.params.agentUrl;
@@ -1175,7 +1826,7 @@ function createWorldApp(world) {
1175
1826
  });
1176
1827
  });
1177
1828
  app.use((err, req, res, next) => {
1178
- logger5.error("Server error:", err);
1829
+ logger10.error("Server error:", err);
1179
1830
  res.status(500).json({
1180
1831
  error: "Internal server error",
1181
1832
  message: err.message
@@ -1187,27 +1838,29 @@ async function startWorldServer(world) {
1187
1838
  const app = createWorldApp(world);
1188
1839
  const server = app.listen(world.config.server.port, world.config.server.host, () => {
1189
1840
  const { host, port } = world.config.server;
1190
- logger5.info(`World "${world.config.name}" server started`);
1191
- logger5.info(` http://${host}:${port}`);
1192
- logger5.info("");
1193
- logger5.info("Endpoints:");
1194
- logger5.info(` GET / - World info`);
1195
- logger5.info(` POST /world/join - Agent join request`);
1196
- logger5.info(` GET /world/agents - List agents`);
1197
- logger5.info(` GET /world/state - World state`);
1198
- logger5.info(` POST /world/start - Start simulation`);
1199
- logger5.info(` POST /world/stop - Stop simulation`);
1200
- logger5.info(` DELETE /world/agents/:url - Remove agent`);
1841
+ logger10.info(`World "${world.config.name}" server started`);
1842
+ logger10.info(` http://${host}:${port}`);
1843
+ logger10.info("");
1844
+ logger10.info("Endpoints:");
1845
+ logger10.info(` GET / - World info`);
1846
+ logger10.info(` POST /world/join - Agent join request`);
1847
+ logger10.info(` GET /world/agents - List agents`);
1848
+ logger10.info(` GET /world/state - World state`);
1849
+ logger10.info(` GET /world/actions - List world actions`);
1850
+ logger10.info(` POST /world/message - Route agent messages`);
1851
+ logger10.info(` POST /world/start - Start simulation`);
1852
+ logger10.info(` POST /world/stop - Stop simulation`);
1853
+ logger10.info(` DELETE /world/agents/:url - Remove agent`);
1201
1854
  });
1202
1855
  process.on("SIGTERM", async () => {
1203
- logger5.info("SIGTERM received, shutting down gracefully...");
1856
+ logger10.info("SIGTERM received, shutting down gracefully...");
1204
1857
  server.close(async () => {
1205
1858
  await world.stop();
1206
1859
  process.exit(0);
1207
1860
  });
1208
1861
  });
1209
1862
  process.on("SIGINT", async () => {
1210
- logger5.info("SIGINT received, shutting down gracefully...");
1863
+ logger10.info("SIGINT received, shutting down gracefully...");
1211
1864
  server.close(async () => {
1212
1865
  await world.stop();
1213
1866
  process.exit(0);
@@ -1215,15 +1868,20 @@ async function startWorldServer(world) {
1215
1868
  });
1216
1869
  }
1217
1870
  export {
1871
+ ActionProcessor,
1218
1872
  AdmissionRulesSchema,
1219
1873
  AgentEvaluator,
1220
1874
  BlockchainClient,
1221
1875
  BlockchainConfigSchema,
1222
1876
  CardFetcher,
1223
1877
  InMemoryAdapter,
1878
+ MessageRouter,
1224
1879
  PersistenceConfigSchema,
1880
+ TickOrchestrator,
1225
1881
  TokenConfigSchema,
1226
1882
  World,
1883
+ WorldA2AClient,
1884
+ WorldActionsRegistry,
1227
1885
  WorldConfigSchema,
1228
1886
  createLogger,
1229
1887
  createPersistence,