mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-05-20 07:17: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 {
|
if !resp.OK {
|
||||||
t.Fatalf("expected ok response, got %+v", resp)
|
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)
|
t.Fatalf("unexpected result: %+v", resp.Payload)
|
||||||
}
|
}
|
||||||
if got := strings.TrimSpace(resp.Payload["agent_id"].(string)); got != "main" {
|
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 {
|
if err := wr.ensureMainProfile(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
wr.ensureStarterWorld(state)
|
||||||
if !wr.autonomyEnabled() {
|
if !wr.autonomyEnabled() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -141,6 +142,49 @@ func (wr *WorldRuntime) ensureAutonomousSeed(state *world.WorldState, npcStates
|
|||||||
return nil
|
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 {
|
func roomIDForQuest(questID string) string {
|
||||||
questID = normalizeWorldID(questID)
|
questID = normalizeWorldID(questID)
|
||||||
if 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)
|
next := wr.engine.EnsureNPCState(wr.profileBlueprint(profile), current)
|
||||||
npcStates[profile.AgentID] = next
|
npcStates[profile.AgentID] = next
|
||||||
}
|
}
|
||||||
|
wr.ensureStarterWorld(&state)
|
||||||
wr.syncQuestRooms(&state, npcStates)
|
wr.syncQuestRooms(&state, npcStates)
|
||||||
if err := wr.store.SaveNPCStates(npcStates); err != nil {
|
if err := wr.store.SaveNPCStates(npcStates); err != nil {
|
||||||
return world.WorldState{}, nil, err
|
return world.WorldState{}, nil, err
|
||||||
@@ -1424,6 +1469,10 @@ func (wr *WorldRuntime) worldProfiles() ([]tools.AgentProfile, error) {
|
|||||||
if !strings.EqualFold(strings.TrimSpace(item.Status), "active") {
|
if !strings.EqualFold(strings.TrimSpace(item.Status), "active") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if strings.EqualFold(strings.TrimSpace(item.AgentID), "main") {
|
||||||
|
out = append(out, worldMindProfile(item))
|
||||||
|
continue
|
||||||
|
}
|
||||||
if !isWorldNPCProfile(item) {
|
if !isWorldNPCProfile(item) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -1443,6 +1492,34 @@ func isWorldNPCProfile(profile tools.AgentProfile) bool {
|
|||||||
len(profile.WorldTags) > 0
|
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 {
|
func (wr *WorldRuntime) profileBlueprint(profile tools.AgentProfile) world.NPCBlueprint {
|
||||||
return world.NPCBlueprint{
|
return world.NPCBlueprint{
|
||||||
NPCID: profile.AgentID,
|
NPCID: profile.AgentID,
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ func TestWorldRuntimeHandleUserInputInitializesState(t *testing.T) {
|
|||||||
t.Fatalf("snapshot failed: %v", err)
|
t.Fatalf("snapshot failed: %v", err)
|
||||||
}
|
}
|
||||||
data, _ := json.Marshal(snapshot)
|
data, _ := json.Marshal(snapshot)
|
||||||
if !strings.Contains(string(data), "\"npc_count\":1") {
|
if !strings.Contains(string(data), "\"npc_count\":2") {
|
||||||
t.Fatalf("expected snapshot npc_count=1, got %s", string(data))
|
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) {
|
func TestWorldRuntimeUpdateEntityPlacement(t *testing.T) {
|
||||||
workspace := t.TempDir()
|
workspace := t.TempDir()
|
||||||
manager := tools.NewAgentManager(nil, workspace, nil)
|
manager := tools.NewAgentManager(nil, workspace, nil)
|
||||||
@@ -303,7 +342,7 @@ func TestWorldRuntimeSnapshotIncludesEntityOccupancyAfterInteract(t *testing.T)
|
|||||||
t.Fatalf("snapshot failed: %v", err)
|
t.Fatalf("snapshot failed: %v", err)
|
||||||
}
|
}
|
||||||
data, _ := json.Marshal(snap)
|
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))
|
t.Fatalf("expected entity occupancy for statue, got %s", string(data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user