File indexing completed on 2026-04-25 08:29:12
0001
0002 """
0003 Load AI dialogue history at Claude Code session start.
0004
0005 Called by Claude Code SessionStart hook to inject recent conversation
0006 context into the new session.
0007
0008 Environment:
0009 SWF_DIALOGUE_TURNS: Number of turns to load (default: 0 = disabled)
0010 SWF_MONITOR_HTTP_URL: Monitor API URL (default: http://pandaserver02.sdcc.bnl.gov/swf-monitor)
0011
0012 Output:
0013 Prints formatted dialogue history to stdout (injected into Claude's context)
0014 """
0015
0016 import json
0017 import os
0018 import sys
0019 import getpass
0020 from pathlib import Path
0021 from typing import Optional
0022
0023
0024 def get_turns_setting():
0025
0026 try:
0027 return int(os.getenv('SWF_DIALOGUE_TURNS', '0'))
0028 except ValueError:
0029 return 0
0030
0031
0032 def load_sysprompt(cwd):
0033
0034 sysprompt_path = Path(cwd) / 'SYSPROMPT.md'
0035 if sysprompt_path.exists():
0036 try:
0037 return sysprompt_path.read_text()
0038 except Exception:
0039 pass
0040 return None
0041
0042
0043 def load_dialogue_via_api(username, turns, namespace=None):
0044
0045 import urllib.request
0046 import urllib.error
0047
0048 base_url = os.getenv('SWF_MONITOR_HTTP_URL', 'http://pandaserver02.sdcc.bnl.gov/swf-monitor')
0049 params = "username={}&turns={}".format(username, turns)
0050 if namespace:
0051 params += "&namespace={}".format(namespace)
0052 url = "{}/api/ai-memory/?{}".format(base_url.rstrip('/'), params)
0053
0054 try:
0055 req = urllib.request.Request(url, method='GET')
0056 with urllib.request.urlopen(req, timeout=5) as resp:
0057 if resp.status == 200:
0058 data = json.loads(resp.read().decode('utf-8'))
0059 return data.get('items', [])
0060 except (urllib.error.URLError, urllib.error.HTTPError, OSError, json.JSONDecodeError):
0061 pass
0062
0063 return []
0064
0065
0066 def format_dialogue(messages):
0067
0068 if not messages:
0069 return ""
0070
0071 lines = ["## Recent Conversation History", ""]
0072 for msg in messages:
0073 role = msg.get('role', 'unknown').upper()
0074 content = msg.get('content', '')
0075 if len(content) > 2000:
0076 content = content[:2000] + "... [truncated]"
0077 lines.append("**{}:** {}".format(role, content))
0078 lines.append("")
0079
0080 return "\n".join(lines)
0081
0082
0083 def get_namespace(cwd):
0084
0085 testbed_toml = os.path.join(cwd, 'workflows', 'testbed.toml')
0086 if not os.path.exists(testbed_toml):
0087 return None
0088 try:
0089 try:
0090 import tomllib
0091 with open(testbed_toml, 'rb') as f:
0092 data = tomllib.load(f)
0093 return data.get('testbed', {}).get('namespace')
0094 except ImportError:
0095 with open(testbed_toml, 'r') as f:
0096 for line in f:
0097 line = line.strip()
0098 if line.startswith('namespace'):
0099 parts = line.split('=', 1)
0100 if len(parts) == 2:
0101 return parts[1].strip().strip('"').strip("'")
0102 except Exception:
0103 pass
0104 return None
0105
0106
0107 def main():
0108 try:
0109 hook_input = json.load(sys.stdin)
0110 except json.JSONDecodeError:
0111 sys.exit(0)
0112
0113 source = hook_input.get('source', '')
0114 if source not in ('startup', 'resume'):
0115 sys.exit(0)
0116
0117 cwd = hook_input.get('cwd', os.getcwd())
0118 username = getpass.getuser()
0119 namespace = get_namespace(cwd)
0120
0121 output_parts = []
0122
0123 sysprompt = load_sysprompt(cwd)
0124 if sysprompt:
0125 output_parts.append(sysprompt)
0126
0127 turns = get_turns_setting()
0128 if turns > 0:
0129 messages = load_dialogue_via_api(username, turns, namespace)
0130 if messages:
0131 dialogue = format_dialogue(messages)
0132 if dialogue:
0133 output_parts.append(dialogue)
0134
0135 if output_parts:
0136 print("\n\n".join(output_parts))
0137
0138 sys.exit(0)
0139
0140
0141 if __name__ == '__main__':
0142 main()