epsimo-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/SKILL.md +85 -0
  3. package/assets/example_asset.txt +24 -0
  4. package/epsimo/__init__.py +3 -0
  5. package/epsimo/__main__.py +4 -0
  6. package/epsimo/auth.py +143 -0
  7. package/epsimo/cli.py +586 -0
  8. package/epsimo/client.py +53 -0
  9. package/epsimo/resources/assistants.py +47 -0
  10. package/epsimo/resources/credits.py +16 -0
  11. package/epsimo/resources/db.py +31 -0
  12. package/epsimo/resources/files.py +39 -0
  13. package/epsimo/resources/projects.py +30 -0
  14. package/epsimo/resources/threads.py +83 -0
  15. package/epsimo/templates/components/AuthModal/AuthModal.module.css +39 -0
  16. package/epsimo/templates/components/AuthModal/AuthModal.tsx +138 -0
  17. package/epsimo/templates/components/BuyCredits/BuyCreditsModal.module.css +96 -0
  18. package/epsimo/templates/components/BuyCredits/BuyCreditsModal.tsx +132 -0
  19. package/epsimo/templates/components/BuyCredits/CreditsDisplay.tsx +101 -0
  20. package/epsimo/templates/components/ThreadChat/ThreadChat.module.css +551 -0
  21. package/epsimo/templates/components/ThreadChat/ThreadChat.tsx +862 -0
  22. package/epsimo/templates/components/ThreadChat/components/ToolRenderers.module.css +509 -0
  23. package/epsimo/templates/components/ThreadChat/components/ToolRenderers.tsx +322 -0
  24. package/epsimo/templates/next-mvp/app/globals.css.tmpl +20 -0
  25. package/epsimo/templates/next-mvp/app/layout.tsx.tmpl +22 -0
  26. package/epsimo/templates/next-mvp/app/page.module.css.tmpl +84 -0
  27. package/epsimo/templates/next-mvp/app/page.tsx.tmpl +43 -0
  28. package/epsimo/templates/next-mvp/epsimo.yaml.tmpl +12 -0
  29. package/epsimo/templates/next-mvp/package.json.tmpl +26 -0
  30. package/epsimo/tools/library.yaml +51 -0
  31. package/package.json +27 -0
  32. package/references/api_reference.md +34 -0
  33. package/references/virtual_db_guide.md +57 -0
  34. package/requirements.txt +2 -0
  35. package/scripts/assistant.py +165 -0
  36. package/scripts/auth.py +195 -0
  37. package/scripts/credits.py +107 -0
  38. package/scripts/debug_run.py +41 -0
  39. package/scripts/example.py +19 -0
  40. package/scripts/files.py +73 -0
  41. package/scripts/find_thread.py +55 -0
  42. package/scripts/project.py +60 -0
  43. package/scripts/run.py +75 -0
  44. package/scripts/test_all_skills.py +387 -0
  45. package/scripts/test_sdk.py +83 -0
  46. package/scripts/test_streaming.py +167 -0
  47. package/scripts/test_vdb.py +65 -0
  48. package/scripts/thread.py +77 -0
  49. package/scripts/verify_skill.py +87 -0
@@ -0,0 +1,167 @@
1
+
2
+ import sys
3
+ import json
4
+ import time
5
+ import requests
6
+ import uuid
7
+ from auth import get_token, get_project_token, API_BASE_URL
8
+
9
+ # --- Colors for Output ---
10
+ class Colors:
11
+ HEADER = '\033[95m'
12
+ OKGREEN = '\033[92m'
13
+ OKCYAN = '\033[96m'
14
+ FAIL = '\033[91m'
15
+ ENDC = '\033[0m'
16
+ BOLD = '\033[1m'
17
+
18
+ def print_pass(msg):
19
+ print(f"{Colors.OKGREEN}āœ… {msg}{Colors.ENDC}")
20
+
21
+ def print_fail(msg):
22
+ print(f"{Colors.FAIL}āŒ {msg}{Colors.ENDC}")
23
+
24
+ def print_info(msg):
25
+ print(f"{Colors.OKCYAN}ā„¹ļø {msg}{Colors.ENDC}")
26
+
27
+ def run_streaming_test():
28
+ print(f"{Colors.HEADER}=== Starting Assistant Streaming Verification ==={Colors.ENDC}")
29
+
30
+ # 1. Auth
31
+ try:
32
+ token = get_token()
33
+ print_pass("Authenticated")
34
+ except Exception as e:
35
+ print_fail(f"Auth failed: {e}")
36
+ return
37
+
38
+ # 2. Project
39
+ project_name = f"StreamTest {int(time.time())}"
40
+ print_info(f"Creating project '{project_name}'...")
41
+ headers = {"Authorization": f"Bearer {token}"}
42
+
43
+ try:
44
+ resp = requests.post(f"{API_BASE_URL}/projects/", headers=headers, json={"name": project_name, "description": "Streaming test"})
45
+ resp.raise_for_status()
46
+ project_id = resp.json()["project_id"]
47
+ project_token = get_project_token(project_id)
48
+ print_pass(f"Project created: {project_id}")
49
+ except Exception as e:
50
+ print_fail(f"Project creation failed: {e}")
51
+ return
52
+
53
+ # 3. Assistant
54
+ print_info("Creating simple assistant...")
55
+ p_headers = {"Authorization": f"Bearer {project_token}"}
56
+
57
+ asst_payload = {
58
+ "name": "Streaming Bot",
59
+ "config": {
60
+ "configurable": {
61
+ "type": "agent",
62
+ "type==agent/agent_type": "GPT-4O",
63
+ "type==agent/model": "gpt-4o",
64
+ "type==agent/system_message": "You are a helpful assistant. If asked to say something, say it exactly."
65
+ }
66
+ },
67
+ "public": False
68
+ }
69
+
70
+ try:
71
+ resp = requests.post(f"{API_BASE_URL}/assistants/", headers=p_headers, json=asst_payload)
72
+ resp.raise_for_status()
73
+ assistant_id = resp.json()["assistant_id"]
74
+ print_pass(f"Assistant created: {assistant_id}")
75
+ except Exception as e:
76
+ print_fail(f"Assistant creation failed: {e}")
77
+ return
78
+
79
+ # 4. Thread
80
+ print_info("Creating thread...")
81
+ try:
82
+ resp = requests.post(f"{API_BASE_URL}/threads/", headers=p_headers, json={"name": "Stream Thread", "assistant_id": assistant_id})
83
+ resp.raise_for_status()
84
+ thread_id = resp.json()["thread_id"]
85
+ print_pass(f"Thread created: {thread_id}")
86
+ except Exception as e:
87
+ print_fail(f"Thread creation failed: {e}")
88
+ return
89
+
90
+ # 5. Streaming Run
91
+ print_info("Ref: sending message 'Say: STREAMING_WORKS'...")
92
+
93
+ stream_headers = {
94
+ "Authorization": f"Bearer {project_token}",
95
+ "Accept": "text/event-stream"
96
+ }
97
+
98
+ run_payload = {
99
+ "thread_id": thread_id,
100
+ "assistant_id": assistant_id,
101
+ "input": [{"role": "user", "content": "Say: STREAMING_WORKS", "type": "human"}],
102
+ "stream_mode": ["messages", "values"]
103
+ }
104
+
105
+ full_text = ""
106
+ print(f"{Colors.OKCYAN}--- Stream Output Start ---{Colors.ENDC}")
107
+
108
+ try:
109
+ with requests.post(f"{API_BASE_URL}/runs/stream", headers=stream_headers, json=run_payload, stream=True) as r:
110
+ r.raise_for_status()
111
+ for line in r.iter_lines():
112
+ if line:
113
+ decoded = line.decode('utf-8')
114
+ if decoded.startswith("data:"):
115
+ data_str = decoded[5:].strip()
116
+ if data_str == "[DONE]":
117
+ break
118
+ try:
119
+ # Attempt to parse json to find content (structure varies, so we print raw for debug if needed)
120
+ # Or just heuristic text accumulation
121
+ # Epsimo / LangGraph usually sends complex JSONs
122
+ data_json = json.loads(data_str)
123
+
124
+ # Heuristic extraction for various formats
125
+ content = ""
126
+ if isinstance(data_json, list): # Often a list of ops
127
+ for item in data_json:
128
+ if "content" in item:
129
+ content = item["content"]
130
+ elif isinstance(data_json, dict):
131
+ if "messages" in data_json:
132
+ # Extract last message content
133
+ pass
134
+ if "content" in data_json:
135
+ content = data_json["content"]
136
+
137
+ # Simple visual echo
138
+ if content:
139
+ sys.stdout.write(content)
140
+ sys.stdout.flush()
141
+ full_text += content
142
+ else:
143
+ # Fallback if we can't parse structure easily, just check raw for test
144
+ pass
145
+ except:
146
+ pass
147
+
148
+ print(f"\n{Colors.OKCYAN}--- Stream Output End ---{Colors.ENDC}")
149
+
150
+ if "STREAMING_WORKS" in full_text:
151
+ print_pass("Verification Successful: Received expected output!")
152
+ else:
153
+ print_fail("Did not receive exact expected phrase, but stream finished.")
154
+ print_info(f"Received total length: {len(full_text)}")
155
+
156
+ except Exception as e:
157
+ print_fail(f"Streaming failed: {e}")
158
+
159
+ # 6. Cleanup
160
+ try:
161
+ requests.delete(f"{API_BASE_URL}/projects/{project_id}?confirm=true", headers=headers)
162
+ print_pass("Cleanup: Project deleted")
163
+ except:
164
+ pass
165
+
166
+ if __name__ == "__main__":
167
+ run_streaming_test()
@@ -0,0 +1,65 @@
1
+ import sys
2
+ import os
3
+ import json
4
+
5
+ # Add parent dir to path to find epsimo package
6
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
7
+
8
+ from epsimo import EpsimoClient
9
+ from epsimo.auth import get_token
10
+
11
+ def test_vdb():
12
+ print("🧪 Testing Virtual Database via Threads...")
13
+
14
+ # Needs a real project and thread from the user's environment
15
+ PROJECT_ID = "cb323eb1-768e-4702-b7af-c73a1d6ce0e1"
16
+
17
+ try:
18
+ token = get_token()
19
+ client = EpsimoClient(api_key=token)
20
+
21
+ # 1. Create a fresh thread for DB testing
22
+ print("Creating fresh DB thread...")
23
+ # Get an assistant first
24
+ assistants = client.assistants.list(PROJECT_ID)
25
+ if not assistants:
26
+ print("āŒ No assistants found in project.")
27
+ return
28
+
29
+ asst_id = assistants[0]["assistant_id"]
30
+ thread = client.threads.create(PROJECT_ID, "Virtual DB Test", asst_id)
31
+ thread_id = thread["thread_id"]
32
+ print(f"āœ… Thread Created: {thread_id}")
33
+
34
+ # 2. Set some structured data
35
+ print("Setting data in DB...")
36
+ db_data = {
37
+ "user_settings": {
38
+ "theme": "dark",
39
+ "notifications": True
40
+ },
41
+ "last_login": "2026-02-03",
42
+ "active_session": True
43
+ }
44
+
45
+ client.threads.set_state(PROJECT_ID, thread_id, db_data)
46
+ print("āœ… Data persisted.")
47
+
48
+ # 3. Retrieve and verify
49
+ print("Querying DB...")
50
+ state = client.threads.get_state(PROJECT_ID, thread_id)
51
+ values = state.get("values", {})
52
+
53
+ print("\n=== Virtual DB Content ===")
54
+ print(json.dumps(values, indent=2))
55
+
56
+ if values.get("user_settings", {}).get("theme") == "dark":
57
+ print("\nšŸŽ‰ SUCCESS: Virtual Database is working correctly!")
58
+ else:
59
+ print("\nāŒ FAILURE: Data mismatch or not found.")
60
+
61
+ except Exception as e:
62
+ print(f"āŒ Test Failed: {e}")
63
+
64
+ if __name__ == "__main__":
65
+ test_vdb()
@@ -0,0 +1,77 @@
1
+
2
+ import os
3
+ import sys
4
+ import argparse
5
+ import requests
6
+ import json
7
+ from auth import get_token, get_project_token, API_BASE_URL
8
+
9
+ def create_thread(project_id, name, assistant_id=None):
10
+ token = get_token()
11
+
12
+ # Get project specific token
13
+ project_token = get_project_token(project_id)
14
+
15
+ headers = {"Authorization": f"Bearer {project_token}"}
16
+
17
+ # Metadata structure from frontend
18
+ payload = {
19
+ "name": name,
20
+ "metadata": {
21
+ "configurable": {},
22
+ "type": "thread"
23
+ },
24
+ "configurable": {
25
+ "type": "agent"
26
+ }
27
+ }
28
+ if assistant_id:
29
+ payload["assistant_id"] = assistant_id
30
+
31
+ response = requests.post(f"{API_BASE_URL}/threads/", headers=headers, json=payload)
32
+
33
+ if not response.ok:
34
+ print(f"Status: {response.status_code}")
35
+ print(f"Body: {response.text}")
36
+
37
+ response.raise_for_status()
38
+ print(json.dumps(response.json(), indent=2))
39
+
40
+ def list_threads(project_id):
41
+ token = get_token()
42
+
43
+ # Get project specific token
44
+ auth_headers = {"Authorization": f"Bearer {token}"}
45
+ proj_resp = requests.get(f"{API_BASE_URL}/projects/{project_id}", headers=auth_headers)
46
+ proj_resp.raise_for_status()
47
+ data = proj_resp.json()
48
+ project_token = data.get('access_token') or data.get('token') or data.get('jwt_token')
49
+
50
+ headers = {"Authorization": f"Bearer {project_token}"}
51
+ response = requests.get(f"{API_BASE_URL}/threads/", headers=headers)
52
+ response.raise_for_status()
53
+ print(json.dumps(response.json(), indent=2))
54
+
55
+ def main():
56
+ parser = argparse.ArgumentParser(description="Manage EpsimoAI Threads")
57
+ subparsers = parser.add_subparsers(dest="command", required=True)
58
+
59
+ # List
60
+ list_parser = subparsers.add_parser("list", help="List threads in a project")
61
+ list_parser.add_argument("--project-id", required=True, help="Project ID")
62
+
63
+ # Create
64
+ create_parser = subparsers.add_parser("create", help="Create a new thread")
65
+ create_parser.add_argument("--project-id", required=True, help="Project ID")
66
+ create_parser.add_argument("--name", default="New Thread", help="Thread name")
67
+ create_parser.add_argument("--assistant-id", help="Assistant ID to associate with the thread (optional)")
68
+
69
+ args = parser.parse_args()
70
+
71
+ if args.command == "list":
72
+ list_threads(args.project_id)
73
+ elif args.command == "create":
74
+ create_thread(args.project_id, args.name, args.assistant_id)
75
+
76
+ if __name__ == "__main__":
77
+ main()
@@ -0,0 +1,87 @@
1
+
2
+ import subprocess
3
+ import sys
4
+ import json
5
+ import time
6
+ import os
7
+ import shutil
8
+
9
+ def run_command(cmd, capture_output=True):
10
+ print(f"Running: {cmd}")
11
+ # Add PYTHONPATH to find epsimo package
12
+ env = os.environ.copy()
13
+ env["PYTHONPATH"] = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
14
+
15
+ result = subprocess.run(cmd, shell=True, capture_output=capture_output, text=True, env=env)
16
+ if result.returncode != 0:
17
+ print(f"Error: {result.stderr}")
18
+ raise Exception(f"Command failed: {cmd}")
19
+ return result.stdout.strip()
20
+
21
+ def main():
22
+ print("šŸš€ Starting Epsimo Agent Skill Verification (CLI Version)...")
23
+
24
+ # 1. Auth Check - we do this in the root to ensure we have credentials
25
+ print("\n1ļøāƒ£ Checking Authentication...")
26
+ try:
27
+ run_command("python3 -m epsimo.cli whoami")
28
+ except:
29
+ print("šŸ” Authentication required. Please run 'epsimo auth login' first.")
30
+ sys.exit(1)
31
+
32
+ # Setup temp workspace
33
+ temp_workspace = f"verify-workspace-{int(time.time())}"
34
+ os.makedirs(temp_workspace)
35
+ orig_dir = os.getcwd()
36
+ os.chdir(temp_workspace)
37
+ print(f"šŸ“‚ Created temporary workspace: {temp_workspace}")
38
+
39
+ try:
40
+ # 2. Project Scaffolding
41
+ print("\n2ļøāƒ£ Verifying Project Scaffolding...")
42
+ test_slug = "verify-app"
43
+ run_command(f"python3 -m epsimo.cli create 'Verify App'")
44
+ if os.path.exists(test_slug) and os.path.exists(f"{test_slug}/epsimo.yaml"):
45
+ print("āœ… Scaffolding SUCCESS: App structure created.")
46
+ else:
47
+ raise Exception("App structure missing files.")
48
+
49
+ # 3. End-to-End lifecycle
50
+ print("\n3ļøāƒ£ Verifying Project/Assistant Lifecycle...")
51
+ proj_name = f"VerifyProj-{int(time.time())}"
52
+ run_command(f"python3 -m epsimo.cli init --name '{proj_name}'")
53
+
54
+ with open("epsimo.yaml", "r") as f:
55
+ import yaml
56
+ cfg = yaml.safe_load(f)
57
+ project_id = cfg['project_id']
58
+
59
+ print(f"āœ… Created Project: {project_id}")
60
+
61
+ # Deploy (creates assistant)
62
+ run_command("python3 -m epsimo.cli deploy")
63
+ print("āœ… Deployed Assistant.")
64
+
65
+ # Discovery Check
66
+ asst_json = run_command(f"python3 -m epsimo.cli assistants --project-id {project_id} --json")
67
+ assistants = json.loads(asst_json)
68
+ if not assistants:
69
+ raise Exception("No assistants found after deploy.")
70
+
71
+ print(f"āœ… Discovery SUCCESS: Found {len(assistants)} assistants.")
72
+
73
+ # 4. Logic responsive check
74
+ print("\n4ļøāƒ£ Checking Credits...")
75
+ run_command("python3 -m epsimo.cli credits balance")
76
+ print("āœ… Logic Check: Responsive.")
77
+
78
+ finally:
79
+ os.chdir(orig_dir)
80
+ if os.path.exists(temp_workspace):
81
+ shutil.rmtree(temp_workspace)
82
+
83
+ print("\nšŸŽ‰ Skill Verification Completed Successfully!")
84
+
85
+ if __name__ == "__main__":
86
+ main()
87
+