11#!/usr/bin/env python3
2- """Dump short- and long-term memory DynamoDB tables as JSON."""
2+ """Dump agent DynamoDB state (events + memories) as JSON."""
33
44import argparse
55import json
66import os
77import sys
88
99import boto3
10- from boto3 .dynamodb .types import TypeDeserializer
10+ from boto3 .dynamodb .conditions import Key
1111
1212
13- def _scan_all ( client , table_name : str ):
14- """Read the entire table via Scan with pagination ."""
13+ def _query_items ( table , partition_key : str ):
14+ """Query all items for a given partition key ."""
1515 items = []
1616 start_key = None
1717 while True :
18- params = {"TableName " : table_name }
18+ params = {"KeyConditionExpression " : Key ( "pk" ). eq ( partition_key ) }
1919 if start_key :
2020 params ["ExclusiveStartKey" ] = start_key
21- resp = client . scan (** params )
21+ resp = table . query (** params )
2222 items .extend (resp .get ("Items" , []))
2323 start_key = resp .get ("LastEvaluatedKey" )
2424 if not start_key :
2525 break
2626 return items
2727
2828
29- def _deserialize_items (raw_items ):
30- deserializer = TypeDeserializer ()
31- return [{k : deserializer .deserialize (v ) for k , v in item .items ()} for item in raw_items ]
29+ def _categorize_items (items ):
30+ buckets = {"events" : [], "memories" : [], "other" : []}
31+ for item in items :
32+ sk = str (item .get ("sk" , "" ))
33+ if "#EVENT#" in sk :
34+ buckets ["events" ].append (item )
35+ elif "#MEMORY#" in sk :
36+ buckets ["memories" ].append (item )
37+ else :
38+ buckets ["other" ].append (item )
39+ return buckets
3240
3341
34- def _dump_table (client , table_name : str , label : str ):
35- raw_items = _scan_all (client , table_name )
42+ def _dump (label : str , table_name : str , agent_id : str , items ):
3643 payload = {
3744 "table" : table_name ,
38- "count" : len (raw_items ),
39- "items" : _deserialize_items (raw_items ),
45+ "agent_id" : agent_id ,
46+ "count" : len (items ),
47+ "items" : items ,
4048 }
41- print (f"# { label } : { table_name } " )
49+ print (f"# { label } (agent_id= { agent_id } ) " )
4250 print (json .dumps (payload , indent = 2 , default = str ))
4351 print ()
4452
@@ -51,34 +59,41 @@ def main():
5159 help = "AWS region for DynamoDB operations (default: %(default)s)" ,
5260 )
5361 parser .add_argument (
54- "--conversation -table" ,
55- default = os .environ .get ("CONVERSATION_TABLE " , "" ),
56- help = "DynamoDB table name for short-term session memory " ,
62+ "--state -table" ,
63+ default = os .environ .get ("AGENT_STATE_TABLE " , "" ),
64+ help = "DynamoDB table name for unified agent state (events + memories) " ,
5765 )
5866 parser .add_argument (
59- "--ais-table " ,
60- default = os .environ .get ("AIS_MEMORY_TABLE " , "" ),
61- help = "DynamoDB table name for long-term AIS memory " ,
67+ "--agent-id " ,
68+ default = os .environ .get ("AGENT_ID " , "marvain-agent " ),
69+ help = "Agent id / partition key suffix to query (default: %(default)s) " ,
6270 )
6371 parser .add_argument (
6472 "--target" ,
65- choices = ["short " , "long " , "both " ],
66- default = "both " ,
67- help = "Select which memory tables to dump (default: both )" ,
73+ choices = ["all " , "events " , "memories" , "other " ],
74+ default = "all " ,
75+ help = "Select which categories to dump (default: all )" ,
6876 )
6977 args = parser .parse_args ()
7078
71- client = boto3 .client ("dynamodb" , region_name = args .region )
79+ if not args .state_table :
80+ sys .exit ("Missing state table name (set AGENT_STATE_TABLE or --state-table)" )
7281
73- if args .target in {"short" , "both" }:
74- if not args .conversation_table :
75- sys .exit ("Missing conversation table name (set CONVERSATION_TABLE or --conversation-table)" )
76- _dump_table (client , args .conversation_table , "Short-term conversation memory" )
82+ dynamodb = boto3 .resource ("dynamodb" , region_name = args .region )
83+ table = dynamodb .Table (args .state_table )
7784
78- if args .target in {"long" , "both" }:
79- if not args .ais_table :
80- sys .exit ("Missing AIS memory table name (set AIS_MEMORY_TABLE or --ais-table)" )
81- _dump_table (client , args .ais_table , "Long-term AIS memory" )
85+ partition_key = f"AGENT#{ args .agent_id } "
86+ items = _query_items (table , partition_key )
87+ buckets = _categorize_items (items )
88+
89+ if args .target in {"events" , "all" }:
90+ _dump ("Events" , args .state_table , args .agent_id , buckets ["events" ])
91+
92+ if args .target in {"memories" , "all" }:
93+ _dump ("Memories" , args .state_table , args .agent_id , buckets ["memories" ])
94+
95+ if args .target in {"other" , "all" }:
96+ _dump ("Other items" , args .state_table , args .agent_id , buckets ["other" ])
8297
8398
8499if __name__ == "__main__" :
0 commit comments