@moltium/world-core 0.1.19 → 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.cjs +724 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +345 -1
- package/dist/index.d.ts +345 -1
- package/dist/index.js +714 -56
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
1370
|
+
logger9.info("Initializing world...");
|
|
805
1371
|
this.setState("initializing");
|
|
806
1372
|
try {
|
|
807
1373
|
if (this.config.persistence) {
|
|
808
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1388
|
+
logger9.info(`Restored ${savedAgents.length} agents from persistence`);
|
|
823
1389
|
}
|
|
824
1390
|
}
|
|
825
1391
|
if (this.config.blockchain) {
|
|
826
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1429
|
+
logger9.warn("World is already running");
|
|
864
1430
|
return;
|
|
865
1431
|
}
|
|
866
|
-
|
|
1432
|
+
logger9.info("Starting world simulation...");
|
|
867
1433
|
this.setState("running");
|
|
868
1434
|
await this.logEvent({
|
|
869
|
-
id:
|
|
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
|
-
|
|
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:
|
|
1461
|
+
id: uuidv43(),
|
|
896
1462
|
type: "world_stopped",
|
|
897
1463
|
timestamp: Date.now()
|
|
898
1464
|
});
|
|
899
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1485
|
+
logger9.info(`Minting membership NFT for agent: ${card.name}`);
|
|
920
1486
|
await this.blockchainClient.mintMembership(walletAddress);
|
|
921
1487
|
} else {
|
|
922
|
-
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
1594
|
+
logger9.debug("Auto-saved world state");
|
|
1015
1595
|
}
|
|
1016
1596
|
}, interval);
|
|
1017
|
-
|
|
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
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
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
|
-
|
|
1631
|
+
logger9.info("Max ticks reached, stopping world");
|
|
1035
1632
|
await this.stop();
|
|
1036
1633
|
}
|
|
1037
1634
|
}, interval);
|
|
1038
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|