yanggan commited on
Commit
06700a4
·
1 Parent(s): d977280

feat: add req/resp history endpoint, fix player_id dynamic binding, remove coordinate info from select_plots

Browse files
Files changed (2) hide show
  1. app.py +78 -2
  2. chinatown/chinatown_agent.py +29 -1
app.py CHANGED
@@ -1,10 +1,86 @@
1
  import os
2
 
3
  from agent_build_sdk.builder import AgentBuilder
 
4
  from chinatown.chinatown_agent import ChinatownLLMAgent
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
  if __name__ == '__main__':
7
  name = 'chinatown'
8
  agent = ChinatownLLMAgent(player_id="")
9
- agent_builder = AgentBuilder(name, agent=agent)
10
- agent_builder.start()
 
 
1
  import os
2
 
3
  from agent_build_sdk.builder import AgentBuilder
4
+ from agent_build_sdk.server.server import EndpointServer
5
  from chinatown.chinatown_agent import ChinatownLLMAgent
6
+ from fastapi.responses import HTMLResponse
7
+ import html as html_lib
8
+
9
+
10
+ def register_debug_endpoints(server: EndpointServer):
11
+ agent = server.agent
12
+
13
+ @server.app.get("/debug/requests")
14
+ def get_requests():
15
+ history = agent.get_req_resp_history()
16
+ return {
17
+ "success": True,
18
+ "total": len(history),
19
+ "history": history,
20
+ }
21
+
22
+ @server.app.get("/debug/requests/view")
23
+ def view_requests():
24
+ history = agent.get_req_resp_history()
25
+ html_items = ""
26
+ for i, item in enumerate(reversed(history)):
27
+ req_data = item.get("req", {})
28
+ resp_data = item.get("resp", {})
29
+ req_type = item.get("type", "?")
30
+ status = req_data.get("status", "?")
31
+ round_num = req_data.get("round", "?")
32
+ action = resp_data.get("action", "-") if resp_data else "-"
33
+
34
+ html_items += f"""
35
+ <div class='req-item'>
36
+ <div class='header'>
37
+ <span class='type'>{req_type}</span>
38
+ <span class='meta'>{html_lib.escape(str(status))} | Round {html_lib.escape(str(round_num))} | Action: {html_lib.escape(str(action))}</span>
39
+ </div>
40
+ <details>
41
+ <summary>Request</summary>
42
+ <pre>{html_lib.escape(str(req_data))}</pre>
43
+ </details>
44
+ <details>
45
+ <summary>Response</summary>
46
+ <pre>{html_lib.escape(str(resp_data))}</pre>
47
+ </details>
48
+ </div>
49
+ """
50
+
51
+ return HTMLResponse(content=f"""
52
+ <!DOCTYPE html>
53
+ <html>
54
+ <head>
55
+ <meta charset='UTF-8'>
56
+ <title>Request/Response History</title>
57
+ <style>
58
+ body {{ font-family: monospace; margin: 20px; background: #f5f5f5; }}
59
+ .req-item {{ background: white; margin: 10px 0; padding: 15px; border-radius: 5px; }}
60
+ .header {{ display: flex; justify-content: space-between; margin-bottom: 10px; }}
61
+ .type {{ font-weight: bold; color: #333; }}
62
+ .meta {{ color: #666; font-size: 0.9em; }}
63
+ details {{ margin: 5px 0; }}
64
+ summary {{ cursor: pointer; color: #0066cc; font-weight: bold; }}
65
+ pre {{ background: #f0f0f0; padding: 10px; overflow-x: auto; white-space: pre-wrap; font-size: 0.85em; }}
66
+ </style>
67
+ </head>
68
+ <body>
69
+ <h2>Request/Response History ({len(history)} items)</h2>
70
+ {html_items}
71
+ </body>
72
+ </html>
73
+ """)
74
+
75
+ @server.app.post("/debug/requests/clear")
76
+ def clear_requests():
77
+ agent.clear_req_resp_history()
78
+ return {"success": True, "message": "请求历史已清空"}
79
+
80
 
81
  if __name__ == '__main__':
82
  name = 'chinatown'
83
  agent = ChinatownLLMAgent(player_id="")
84
+ server = EndpointServer(agent)
85
+ register_debug_endpoints(server)
86
+ server.start()
chinatown/chinatown_agent.py CHANGED
@@ -29,6 +29,7 @@ class ChinatownLLMAgent(ChinatownAgent):
29
  self.player_id = player_id
30
  self._board_stale: bool = False
31
  self._snapshot_version: int = 0
 
32
 
33
  # ================================================================
34
  # Perceive: 接收感知事件, 更新记忆
@@ -38,6 +39,14 @@ class ChinatownLLMAgent(ChinatownAgent):
38
  status_val = req.status.value if hasattr(req.status, "value") else str(req.status)
39
  logger.info(f"[perceive] player={self.player_id}, status={status_val}, round={req.round}")
40
 
 
 
 
 
 
 
 
 
41
  # snapshot 非空代表地图有更新, 标记棋盘脏
42
  if req.snapshot:
43
  self._board_stale = True
@@ -106,10 +115,23 @@ class ChinatownLLMAgent(ChinatownAgent):
106
  }
107
 
108
  def interact(self, req: AgentReq) -> AgentResp:
109
- """基于 LLM 生成交互决策"""
110
  status_val = req.status.value if hasattr(req.status, "value") else str(req.status)
111
  logger.info(f"[interact] player={self.player_id}, status={status_val}, round={req.round}")
112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  # MAP_SYNC: 解析 snapshot 后返回 ACK
114
  if req.status == GamePhase.PHASE_MAP_SYNC:
115
  if req.snapshot:
@@ -138,3 +160,9 @@ class ChinatownLLMAgent(ChinatownAgent):
138
  except Exception as e:
139
  logger.error(f"[interact] EXCEPTION: {e}", exc_info=True)
140
  return AgentResp.failure(str(e))
 
 
 
 
 
 
 
29
  self.player_id = player_id
30
  self._board_stale: bool = False
31
  self._snapshot_version: int = 0
32
+ self._req_resp_history: list = []
33
 
34
  # ================================================================
35
  # Perceive: 接收感知事件, 更新记忆
 
39
  status_val = req.status.value if hasattr(req.status, "value") else str(req.status)
40
  logger.info(f"[perceive] player={self.player_id}, status={status_val}, round={req.round}")
41
 
42
+ self._req_resp_history.append({
43
+ "type": "perceive",
44
+ "req": req.model_dump(),
45
+ "resp": None,
46
+ })
47
+ if len(self._req_resp_history) > 100:
48
+ self._req_resp_history = self._req_resp_history[-100:]
49
+
50
  # snapshot 非空代表地图有更新, 标记棋盘脏
51
  if req.snapshot:
52
  self._board_stale = True
 
115
  }
116
 
117
  def interact(self, req: AgentReq) -> AgentResp:
 
118
  status_val = req.status.value if hasattr(req.status, "value") else str(req.status)
119
  logger.info(f"[interact] player={self.player_id}, status={status_val}, round={req.round}")
120
 
121
+ resp = self._do_interact(req)
122
+
123
+ self._req_resp_history.append({
124
+ "type": "interact",
125
+ "req": req.model_dump(),
126
+ "resp": resp.model_dump(),
127
+ })
128
+ if len(self._req_resp_history) > 100:
129
+ self._req_resp_history = self._req_resp_history[-100:]
130
+
131
+ return resp
132
+
133
+ def _do_interact(self, req: AgentReq) -> AgentResp:
134
+
135
  # MAP_SYNC: 解析 snapshot 后返回 ACK
136
  if req.status == GamePhase.PHASE_MAP_SYNC:
137
  if req.snapshot:
 
160
  except Exception as e:
161
  logger.error(f"[interact] EXCEPTION: {e}", exc_info=True)
162
  return AgentResp.failure(str(e))
163
+
164
+ def get_req_resp_history(self) -> list:
165
+ return self._req_resp_history
166
+
167
+ def clear_req_resp_history(self):
168
+ self._req_resp_history.clear()