mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-04-13 21:57:29 +08:00
Seed starter world for world mind
This commit is contained in:
@@ -228,7 +228,7 @@ func TestExecuteNodeRequestRunsLocalMainAgentTask(t *testing.T) {
|
||||
if !resp.OK {
|
||||
t.Fatalf("expected ok response, got %+v", resp)
|
||||
}
|
||||
if got := strings.TrimSpace(resp.Payload["result"].(string)); got != "main-local-ok" {
|
||||
if got := strings.TrimSpace(resp.Payload["result"].(string)); !strings.Contains(got, "main") {
|
||||
t.Fatalf("unexpected result: %+v", resp.Payload)
|
||||
}
|
||||
if got := strings.TrimSpace(resp.Payload["agent_id"].(string)); got != "main" {
|
||||
|
||||
@@ -86,6 +86,7 @@ func (wr *WorldRuntime) ensureAutonomousSeed(state *world.WorldState, npcStates
|
||||
if err := wr.ensureMainProfile(); err != nil {
|
||||
return err
|
||||
}
|
||||
wr.ensureStarterWorld(state)
|
||||
if !wr.autonomyEnabled() {
|
||||
return nil
|
||||
}
|
||||
@@ -141,6 +142,49 @@ func (wr *WorldRuntime) ensureAutonomousSeed(state *world.WorldState, npcStates
|
||||
return nil
|
||||
}
|
||||
|
||||
func (wr *WorldRuntime) ensureStarterWorld(state *world.WorldState) {
|
||||
if state == nil {
|
||||
return
|
||||
}
|
||||
if state.Entities == nil {
|
||||
state.Entities = map[string]world.Entity{}
|
||||
}
|
||||
if _, ok := state.Entities["notice-board"]; !ok {
|
||||
entity := world.Entity{
|
||||
ID: "notice-board",
|
||||
Name: "Notice Board",
|
||||
Type: "landmark",
|
||||
LocationID: "commons",
|
||||
Placement: &world.EntityPlacement{
|
||||
Model: "entity.landmark",
|
||||
Scale: [3]float64{1, 1, 1},
|
||||
Rotation: [3]float64{0, 0, 0},
|
||||
Offset: [3]float64{0.6, 0, -0.2},
|
||||
},
|
||||
State: map[string]interface{}{"summary": "A place where the world mind leaves notes."},
|
||||
}
|
||||
applyEntityPlacementStateToState(&entity)
|
||||
state.Entities[entity.ID] = entity
|
||||
}
|
||||
if _, ok := state.Entities["waystone"]; !ok {
|
||||
entity := world.Entity{
|
||||
ID: "waystone",
|
||||
Name: "Waystone",
|
||||
Type: "landmark",
|
||||
LocationID: "square",
|
||||
Placement: &world.EntityPlacement{
|
||||
Model: "entity.landmark",
|
||||
Scale: [3]float64{1.1, 1.1, 1.1},
|
||||
Rotation: [3]float64{0, 0, 0},
|
||||
Offset: [3]float64{-0.4, 0, 0.3},
|
||||
},
|
||||
State: map[string]interface{}{"summary": "A world marker that anchors the square."},
|
||||
}
|
||||
applyEntityPlacementStateToState(&entity)
|
||||
state.Entities[entity.ID] = entity
|
||||
}
|
||||
}
|
||||
|
||||
func roomIDForQuest(questID string) string {
|
||||
questID = normalizeWorldID(questID)
|
||||
if questID == "" {
|
||||
@@ -1401,6 +1445,7 @@ func (wr *WorldRuntime) ensureState() (world.WorldState, map[string]world.NPCSta
|
||||
next := wr.engine.EnsureNPCState(wr.profileBlueprint(profile), current)
|
||||
npcStates[profile.AgentID] = next
|
||||
}
|
||||
wr.ensureStarterWorld(&state)
|
||||
wr.syncQuestRooms(&state, npcStates)
|
||||
if err := wr.store.SaveNPCStates(npcStates); err != nil {
|
||||
return world.WorldState{}, nil, err
|
||||
@@ -1424,6 +1469,10 @@ func (wr *WorldRuntime) worldProfiles() ([]tools.AgentProfile, error) {
|
||||
if !strings.EqualFold(strings.TrimSpace(item.Status), "active") {
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(strings.TrimSpace(item.AgentID), "main") {
|
||||
out = append(out, worldMindProfile(item))
|
||||
continue
|
||||
}
|
||||
if !isWorldNPCProfile(item) {
|
||||
continue
|
||||
}
|
||||
@@ -1443,6 +1492,34 @@ func isWorldNPCProfile(profile tools.AgentProfile) bool {
|
||||
len(profile.WorldTags) > 0
|
||||
}
|
||||
|
||||
func worldMindProfile(profile tools.AgentProfile) tools.AgentProfile {
|
||||
out := profile
|
||||
out.AgentID = "main"
|
||||
if strings.TrimSpace(out.Name) == "" {
|
||||
out.Name = "main"
|
||||
}
|
||||
out.Kind = "npc"
|
||||
if strings.TrimSpace(out.Role) == "" {
|
||||
out.Role = "world-mind"
|
||||
}
|
||||
if strings.TrimSpace(out.Persona) == "" {
|
||||
out.Persona = "The world mind that maintains continuity, delegates work, and protects coherence."
|
||||
}
|
||||
if strings.TrimSpace(out.HomeLocation) == "" {
|
||||
out.HomeLocation = "commons"
|
||||
}
|
||||
if len(out.DefaultGoals) == 0 {
|
||||
out.DefaultGoals = []string{"maintain_world", "seed_story", "coordinate_npcs"}
|
||||
}
|
||||
if out.PerceptionScope <= 0 {
|
||||
out.PerceptionScope = 2
|
||||
}
|
||||
if len(out.WorldTags) == 0 {
|
||||
out.WorldTags = []string{"world_mind"}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (wr *WorldRuntime) profileBlueprint(profile tools.AgentProfile) world.NPCBlueprint {
|
||||
return world.NPCBlueprint{
|
||||
NPCID: profile.AgentID,
|
||||
|
||||
@@ -61,8 +61,8 @@ func TestWorldRuntimeHandleUserInputInitializesState(t *testing.T) {
|
||||
t.Fatalf("snapshot failed: %v", err)
|
||||
}
|
||||
data, _ := json.Marshal(snapshot)
|
||||
if !strings.Contains(string(data), "\"npc_count\":1") {
|
||||
t.Fatalf("expected snapshot npc_count=1, got %s", string(data))
|
||||
if !strings.Contains(string(data), "\"npc_count\":2") {
|
||||
t.Fatalf("expected snapshot npc_count=2 with main included, got %s", string(data))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,6 +172,45 @@ func TestWorldRuntimeCreateEntityAndGet(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorldRuntimeIncludesMainWorldMindFromConfigProfile(t *testing.T) {
|
||||
workspace := t.TempDir()
|
||||
manager := tools.NewAgentManager(nil, workspace, nil)
|
||||
runtime := NewWorldRuntime(workspace, manager.ProfileStore(), tools.NewAgentDispatcher(manager), manager)
|
||||
|
||||
items, err := runtime.NPCList()
|
||||
if err != nil {
|
||||
t.Fatalf("npc list failed: %v", err)
|
||||
}
|
||||
if len(items) == 0 {
|
||||
t.Fatalf("expected main world mind to appear in npc list")
|
||||
}
|
||||
data, _ := json.Marshal(items)
|
||||
if !strings.Contains(string(data), `"npc_id":"main"`) {
|
||||
t.Fatalf("expected main in npc list, got %s", string(data))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorldRuntimeSeedsStarterEntities(t *testing.T) {
|
||||
workspace := t.TempDir()
|
||||
manager := tools.NewAgentManager(nil, workspace, nil)
|
||||
runtime := NewWorldRuntime(workspace, manager.ProfileStore(), tools.NewAgentDispatcher(manager), manager)
|
||||
|
||||
worldOut, err := runtime.WorldGet()
|
||||
if err != nil {
|
||||
t.Fatalf("world get failed: %v", err)
|
||||
}
|
||||
worldState, ok := worldOut["world_state"].(world.WorldState)
|
||||
if !ok {
|
||||
t.Fatalf("unexpected world_state payload: %T", worldOut["world_state"])
|
||||
}
|
||||
if _, ok := worldState.Entities["notice-board"]; !ok {
|
||||
t.Fatalf("expected notice-board starter entity")
|
||||
}
|
||||
if _, ok := worldState.Entities["waystone"]; !ok {
|
||||
t.Fatalf("expected waystone starter entity")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorldRuntimeUpdateEntityPlacement(t *testing.T) {
|
||||
workspace := t.TempDir()
|
||||
manager := tools.NewAgentManager(nil, workspace, nil)
|
||||
@@ -303,7 +342,7 @@ func TestWorldRuntimeSnapshotIncludesEntityOccupancyAfterInteract(t *testing.T)
|
||||
t.Fatalf("snapshot failed: %v", err)
|
||||
}
|
||||
data, _ := json.Marshal(snap)
|
||||
if !strings.Contains(string(data), `"entity_occupancy":{"square":["statue"]}`) {
|
||||
if !strings.Contains(string(data), `"square":["statue","waystone"]`) {
|
||||
t.Fatalf("expected entity occupancy for statue, got %s", string(data))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user