codeBOKER commited on
Commit
471b8a0
·
1 Parent(s): faa354d

feat: implement illusion account system with is_real variable tracking

Browse files

- Add is_real boolean field to distinguish real vs illusion accounts
- Update get_sender_account() to require user name for illusion account creation
- Add create_illusion_account tool for AI service integration
- Modify transfer functions to use is_real variable instead of name checking
- Include testing disclaimers for illusion account transactions
- Add comprehensive is_real/is_illusion tracking throughout the system
- Update AI service instructions to handle user name requirement for illusion accounts

ai_service.py CHANGED
@@ -8,6 +8,7 @@ from transfers import (
8
  cancel_transfer,
9
  get_pending_transfer,
10
  get_account_balance,
 
11
  )
12
 
13
 
@@ -126,6 +127,23 @@ TOOLS = [
126
  "required": []
127
  }
128
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  }
130
  ]
131
 
@@ -150,6 +168,8 @@ async def run_tool(tool_name: str, args: dict, telegram_id: int):
150
  return json.dumps(cancel_transfer(telegram_id), ensure_ascii=False)
151
  if tool_name == "get_pending_money_transfer":
152
  return json.dumps(get_pending_transfer(telegram_id), ensure_ascii=False)
 
 
153
  return json.dumps({"success": False, "message": f"Unknown tool: {tool_name}"}, ensure_ascii=False)
154
 
155
  async def get_ai_response(user_query: str, telegram_id: int):
@@ -164,11 +184,9 @@ async def get_ai_response(user_query: str, telegram_id: int):
164
 
165
  transfer_instructions = (
166
  f"Current user telegram_id is {telegram_id}. "
167
- "The customer service system cannot create bank accounts. "
168
  "The model must never choose, guess, extract, or override any telegram_id for tool calls. "
169
  "Always act only for the current authenticated user from server-side request context. "
170
  "If the user asks for another person's balance or provides another person's telegram ID, refuse and explain that you can only access the current user's own account. "
171
- "If the sender does not already have a bank account, clearly tell them they must visit the bank to create one. "
172
  "If the user asks for their balance, call check_account_balance. "
173
  "For money transfers, first collect the receiver account serial ID and the amount if it is missing. "
174
  "Then call prepare_money_transfer to fetch the receiver name and store the pending transfer. "
@@ -176,6 +194,9 @@ async def get_ai_response(user_query: str, telegram_id: int):
176
  "Only call confirm_money_transfer after the user clearly agrees. "
177
  "If the user rejects the receiver or wants to stop, call cancel_money_transfer. "
178
  "Never claim a transfer is completed unless confirm_money_transfer returns success."
 
 
 
179
  )
180
  messages = [{"role": "system", "content": f"{BASE_PROMPT}\n\n{transfer_instructions}"}] + conversation_history + [{"role": "user", "content": user_query}]
181
 
 
8
  cancel_transfer,
9
  get_pending_transfer,
10
  get_account_balance,
11
+ get_sender_account,
12
  )
13
 
14
 
 
127
  "required": []
128
  }
129
  }
130
+ },
131
+ {
132
+ "type": "function",
133
+ "function": {
134
+ "name": "create_illusion_account",
135
+ "description": "Use this tool when the user needs an illusion account created for testing purposes. Requires the user's name.",
136
+ "parameters": {
137
+ "type": "object",
138
+ "properties": {
139
+ "user_name": {
140
+ "type": "string",
141
+ "description": "The name of the user for the illusion account."
142
+ }
143
+ },
144
+ "required": ["user_name"]
145
+ }
146
+ }
147
  }
148
  ]
149
 
 
168
  return json.dumps(cancel_transfer(telegram_id), ensure_ascii=False)
169
  if tool_name == "get_pending_money_transfer":
170
  return json.dumps(get_pending_transfer(telegram_id), ensure_ascii=False)
171
+ if tool_name == "create_illusion_account":
172
+ return json.dumps(get_sender_account(telegram_id, args["user_name"]), ensure_ascii=False)
173
  return json.dumps({"success": False, "message": f"Unknown tool: {tool_name}"}, ensure_ascii=False)
174
 
175
  async def get_ai_response(user_query: str, telegram_id: int):
 
184
 
185
  transfer_instructions = (
186
  f"Current user telegram_id is {telegram_id}. "
 
187
  "The model must never choose, guess, extract, or override any telegram_id for tool calls. "
188
  "Always act only for the current authenticated user from server-side request context. "
189
  "If the user asks for another person's balance or provides another person's telegram ID, refuse and explain that you can only access the current user's own account. "
 
190
  "If the user asks for their balance, call check_account_balance. "
191
  "For money transfers, first collect the receiver account serial ID and the amount if it is missing. "
192
  "Then call prepare_money_transfer to fetch the receiver name and store the pending transfer. "
 
194
  "Only call confirm_money_transfer after the user clearly agrees. "
195
  "If the user rejects the receiver or wants to stop, call cancel_money_transfer. "
196
  "Never claim a transfer is completed unless confirm_money_transfer returns success."
197
+ "If a tool result returns 'need_user_name': true, ask the user for their name and then call create_illusion_account with their name. "
198
+ "If a tool result indicates an illusion account was created (contains 'is_illusion': true or mentions testing), inform the user that an illusion account with 2000 YER balance was created for testing purposes. "
199
+ "If confirm_money_transfer returns a result with 'is_illusion': true, make sure to display the testing disclaimer message to the user."
200
  )
201
  messages = [{"role": "system", "content": f"{BASE_PROMPT}\n\n{transfer_instructions}"}] + conversation_history + [{"role": "user", "content": user_query}]
202
 
transfers/__init__.py CHANGED
@@ -3,6 +3,7 @@ from .service import (
3
  confirm_transfer,
4
  get_account_balance,
5
  get_pending_transfer,
 
6
  prepare_transfer,
7
  )
8
 
 
3
  confirm_transfer,
4
  get_account_balance,
5
  get_pending_transfer,
6
+ get_sender_account,
7
  prepare_transfer,
8
  )
9
 
transfers/mock_bank_accounts.json CHANGED
@@ -6,15 +6,17 @@
6
  "serial_id": "1001",
7
  "name": "Test Sender",
8
  "balance": 1900.0,
9
- "currency": "YER"
 
10
  },
11
  {
12
  "telegram_id": 991001,
13
  "account_id": "ACC-991001",
14
  "serial_id": "2001",
15
  "name": "Ahmed Salem",
16
- "balance": 1800.0,
17
- "currency": "YER"
 
18
  },
19
  {
20
  "telegram_id": 991002,
@@ -22,7 +24,8 @@
22
  "serial_id": "2002",
23
  "name": "Mona Ali",
24
  "balance": 800.0,
25
- "currency": "YER"
 
26
  },
27
  {
28
  "telegram_id": 991003,
@@ -30,7 +33,17 @@
30
  "serial_id": "2003",
31
  "name": "Khaled Omar",
32
  "balance": 300.0,
33
- "currency": "YER"
 
 
 
 
 
 
 
 
 
 
34
  }
35
  ],
36
  "transactions": [
@@ -63,6 +76,16 @@
63
  "amount": 200.0,
64
  "currency": "YER",
65
  "created_at": "2026-04-10T19:33:54.495350"
 
 
 
 
 
 
 
 
 
 
66
  }
67
  ]
68
- }
 
6
  "serial_id": "1001",
7
  "name": "Test Sender",
8
  "balance": 1900.0,
9
+ "currency": "YER",
10
+ "is_real": true
11
  },
12
  {
13
  "telegram_id": 991001,
14
  "account_id": "ACC-991001",
15
  "serial_id": "2001",
16
  "name": "Ahmed Salem",
17
+ "balance": 1990.0,
18
+ "currency": "YER",
19
+ "is_real": true
20
  },
21
  {
22
  "telegram_id": 991002,
 
24
  "serial_id": "2002",
25
  "name": "Mona Ali",
26
  "balance": 800.0,
27
+ "currency": "YER",
28
+ "is_real": true
29
  },
30
  {
31
  "telegram_id": 991003,
 
33
  "serial_id": "2003",
34
  "name": "Khaled Omar",
35
  "balance": 300.0,
36
+ "currency": "YER",
37
+ "is_real": true
38
+ },
39
+ {
40
+ "telegram_id": 34,
41
+ "account_id": "ACC-34",
42
+ "serial_id": "9034",
43
+ "name": "Test User Ali",
44
+ "balance": 1810.0,
45
+ "currency": "YER",
46
+ "is_real": false
47
  }
48
  ],
49
  "transactions": [
 
76
  "amount": 200.0,
77
  "currency": "YER",
78
  "created_at": "2026-04-10T19:33:54.495350"
79
+ },
80
+ {
81
+ "transaction_id": "TX-20260420140247475948",
82
+ "telegram_id": 34,
83
+ "sender_serial_id": "9034",
84
+ "receiver_serial_id": "2001",
85
+ "receiver_name": "Ahmed Salem",
86
+ "amount": 190.0,
87
+ "currency": "YER",
88
+ "created_at": "2026-04-20T14:02:47.475998"
89
  }
90
  ]
91
+ }
transfers/service.py CHANGED
@@ -48,19 +48,48 @@ def _find_account_by_serial_id(accounts: list[Dict[str, Any]], serial_id: str) -
48
  return next((account for account in accounts if str(account.get("serial_id")) == normalized_id), None)
49
 
50
 
51
- def get_sender_account(telegram_id: int) -> Dict[str, Any]:
52
  with _LOCK:
53
  data = _load_bank_data()
54
  sender = _find_account_by_telegram_id(data["accounts"], telegram_id)
55
  if sender:
 
 
56
  return {
57
  "success": True,
58
  "account": sender,
 
 
59
  }
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  return {
62
- "success": False,
63
- "message": "You do not have an account in the bank system. Please visit the bank to create an account first.",
 
 
 
64
  }
65
 
66
 
@@ -70,7 +99,7 @@ def get_account_balance(telegram_id: int) -> Dict[str, Any]:
70
  return sender_result
71
 
72
  account = sender_result["account"]
73
- return {
74
  "success": True,
75
  "telegram_id": telegram_id,
76
  "account_id": account["account_id"],
@@ -78,7 +107,14 @@ def get_account_balance(telegram_id: int) -> Dict[str, Any]:
78
  "name": account["name"],
79
  "balance": account.get("balance", 0.0),
80
  "currency": account.get("currency", "YER"),
 
 
81
  }
 
 
 
 
 
82
 
83
 
84
  def get_receiver_account_name(receiver_serial_id: str) -> Dict[str, Any]:
@@ -230,11 +266,21 @@ def confirm_transfer(telegram_id: int) -> Dict[str, Any]:
230
  pending_transfers.pop(str(telegram_id), None)
231
  _save_pending_transfers(pending_transfers)
232
 
 
 
 
 
 
 
 
 
233
  return {
234
  "success": True,
235
  "transaction": transaction,
236
  "sender_balance": sender["balance"],
237
- "message": f"Transfer completed successfully to {receiver['name']}.",
 
 
238
  }
239
 
240
 
 
48
  return next((account for account in accounts if str(account.get("serial_id")) == normalized_id), None)
49
 
50
 
51
+ def get_sender_account(telegram_id: int, user_name: str = None) -> Dict[str, Any]:
52
  with _LOCK:
53
  data = _load_bank_data()
54
  sender = _find_account_by_telegram_id(data["accounts"], telegram_id)
55
  if sender:
56
+ is_real = sender.get("is_real", True)
57
+ is_illusion = not is_real or sender.get("name", "").startswith("Test User")
58
  return {
59
  "success": True,
60
  "account": sender,
61
+ "is_real": is_real,
62
+ "is_illusion": is_illusion,
63
  }
64
 
65
+ # Ask for user name before creating illusion account
66
+ if not user_name:
67
+ return {
68
+ "success": False,
69
+ "need_user_name": True,
70
+ "message": "I need to create an illusion account for testing purposes. What is your name?",
71
+ }
72
+
73
+ # Create illusion account for testing purposes
74
+ new_account = {
75
+ "telegram_id": telegram_id,
76
+ "account_id": f"ACC-{telegram_id}",
77
+ "serial_id": str(9000 + telegram_id % 1000),
78
+ "name": f"Test User {user_name}",
79
+ "balance": 2000.0,
80
+ "currency": "YER",
81
+ "is_real": False
82
+ }
83
+
84
+ data["accounts"].append(new_account)
85
+ _save_bank_data(data)
86
+
87
  return {
88
+ "success": True,
89
+ "account": new_account,
90
+ "is_real": False,
91
+ "is_illusion": True,
92
+ "message": f"I've created an illusion account for {user_name} with 2000 YER balance to try sending money. This is for testing purposes only."
93
  }
94
 
95
 
 
99
  return sender_result
100
 
101
  account = sender_result["account"]
102
+ result = {
103
  "success": True,
104
  "telegram_id": telegram_id,
105
  "account_id": account["account_id"],
 
107
  "name": account["name"],
108
  "balance": account.get("balance", 0.0),
109
  "currency": account.get("currency", "YER"),
110
+ "is_real": sender_result.get("is_real", True),
111
+ "is_illusion": sender_result.get("is_illusion", False),
112
  }
113
+
114
+ if result["is_illusion"]:
115
+ result["message"] = "This is an illusion account created for testing purposes with 2000 YER balance."
116
+
117
+ return result
118
 
119
 
120
  def get_receiver_account_name(receiver_serial_id: str) -> Dict[str, Any]:
 
266
  pending_transfers.pop(str(telegram_id), None)
267
  _save_pending_transfers(pending_transfers)
268
 
269
+ # Check if sender is an illusion account using is_real variable
270
+ is_real = sender.get("is_real", True)
271
+ is_illusion = not is_real
272
+
273
+ message = f"Transfer completed successfully to {receiver['name']}."
274
+ if is_illusion:
275
+ message += " ⚠️ Please note: This process was not real - it was for testing purposes only. No actual money was transferred."
276
+
277
  return {
278
  "success": True,
279
  "transaction": transaction,
280
  "sender_balance": sender["balance"],
281
+ "is_real": is_real,
282
+ "is_illusion": is_illusion,
283
+ "message": message,
284
  }
285
 
286