ursa-ai 0.9.1__py3-none-any.whl

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 (51) hide show
  1. ursa/__init__.py +3 -0
  2. ursa/agents/__init__.py +32 -0
  3. ursa/agents/acquisition_agents.py +812 -0
  4. ursa/agents/arxiv_agent.py +429 -0
  5. ursa/agents/base.py +728 -0
  6. ursa/agents/chat_agent.py +60 -0
  7. ursa/agents/code_review_agent.py +341 -0
  8. ursa/agents/execution_agent.py +915 -0
  9. ursa/agents/hypothesizer_agent.py +614 -0
  10. ursa/agents/lammps_agent.py +465 -0
  11. ursa/agents/mp_agent.py +204 -0
  12. ursa/agents/optimization_agent.py +410 -0
  13. ursa/agents/planning_agent.py +219 -0
  14. ursa/agents/rag_agent.py +304 -0
  15. ursa/agents/recall_agent.py +54 -0
  16. ursa/agents/websearch_agent.py +196 -0
  17. ursa/cli/__init__.py +363 -0
  18. ursa/cli/hitl.py +516 -0
  19. ursa/cli/hitl_api.py +75 -0
  20. ursa/observability/metrics_charts.py +1279 -0
  21. ursa/observability/metrics_io.py +11 -0
  22. ursa/observability/metrics_session.py +750 -0
  23. ursa/observability/pricing.json +97 -0
  24. ursa/observability/pricing.py +321 -0
  25. ursa/observability/timing.py +1466 -0
  26. ursa/prompt_library/__init__.py +0 -0
  27. ursa/prompt_library/code_review_prompts.py +51 -0
  28. ursa/prompt_library/execution_prompts.py +50 -0
  29. ursa/prompt_library/hypothesizer_prompts.py +17 -0
  30. ursa/prompt_library/literature_prompts.py +11 -0
  31. ursa/prompt_library/optimization_prompts.py +131 -0
  32. ursa/prompt_library/planning_prompts.py +79 -0
  33. ursa/prompt_library/websearch_prompts.py +131 -0
  34. ursa/tools/__init__.py +0 -0
  35. ursa/tools/feasibility_checker.py +114 -0
  36. ursa/tools/feasibility_tools.py +1075 -0
  37. ursa/tools/run_command.py +27 -0
  38. ursa/tools/write_code.py +42 -0
  39. ursa/util/__init__.py +0 -0
  40. ursa/util/diff_renderer.py +128 -0
  41. ursa/util/helperFunctions.py +142 -0
  42. ursa/util/logo_generator.py +625 -0
  43. ursa/util/memory_logger.py +183 -0
  44. ursa/util/optimization_schema.py +78 -0
  45. ursa/util/parse.py +405 -0
  46. ursa_ai-0.9.1.dist-info/METADATA +304 -0
  47. ursa_ai-0.9.1.dist-info/RECORD +51 -0
  48. ursa_ai-0.9.1.dist-info/WHEEL +5 -0
  49. ursa_ai-0.9.1.dist-info/entry_points.txt +2 -0
  50. ursa_ai-0.9.1.dist-info/licenses/LICENSE +8 -0
  51. ursa_ai-0.9.1.dist-info/top_level.txt +1 -0
ursa/cli/__init__.py ADDED
@@ -0,0 +1,363 @@
1
+ import importlib
2
+ from pathlib import Path
3
+ from typing import Annotated, Optional
4
+
5
+ from rich.console import Console
6
+ from typer import Exit, Option, Typer, colors, secho
7
+
8
+ app = Typer()
9
+
10
+
11
+ @app.command(help="Start ursa REPL")
12
+ def run(
13
+ workspace: Annotated[
14
+ Path, Option(help="Directory to store ursa ouput")
15
+ ] = Path("ursa_workspace"),
16
+ llm_model_name: Annotated[
17
+ str,
18
+ Option(
19
+ help=(
20
+ "Model provider and name of LLM to use for agent tasks. "
21
+ "Use format <provider>:<model-name>. "
22
+ "For example 'openai:gpt-5'. "
23
+ "See https://reference.langchain.com/python/langchain/models/?h=init_chat_model#langchain.chat_models.init_chat_model"
24
+ ),
25
+ envvar="URSA_LLM_NAME",
26
+ ),
27
+ ] = "openai:gpt-5",
28
+ llm_base_url: Annotated[
29
+ Optional[str],
30
+ Option(help="Base url for LLM.", envvar="URSA_LLM_BASE_URL"),
31
+ ] = None,
32
+ llm_api_key: Annotated[
33
+ Optional[str],
34
+ Option(help="API key for LLM", envvar="URSA_LLM_API_KEY"),
35
+ ] = None,
36
+ max_completion_tokens: Annotated[
37
+ int, Option(help="Maximum tokens for LLM to output")
38
+ ] = 50000,
39
+ emb_model_name: Annotated[
40
+ Optional[str],
41
+ Option(
42
+ help=(
43
+ "Model provider and Embedding model name. "
44
+ "Use format <provider>:<embedding-model-name>. "
45
+ "For example, 'openai:text-embedding-3-small'. "
46
+ "See: https://reference.langchain.com/python/langchain/embeddings/?h=init_embeddings#langchain.embeddings.init_embeddings"
47
+ ),
48
+ envvar="URSA_EMB_NAME",
49
+ ),
50
+ ] = None,
51
+ emb_base_url: Annotated[
52
+ Optional[str],
53
+ Option(help="Base url for embedding model", envvar="URSA_EMB_BASE_URL"),
54
+ ] = None,
55
+ emb_api_key: Annotated[
56
+ Optional[str],
57
+ Option(help="API key for embedding model", envvar="URSA_EMB_API_KEY"),
58
+ ] = None,
59
+ share_key: Annotated[
60
+ bool,
61
+ Option(
62
+ help=(
63
+ "Whether or not the LLM and embedding model share the same "
64
+ "API key. If yes, then you can specify only one of them."
65
+ )
66
+ ),
67
+ ] = False,
68
+ thread_id: Annotated[
69
+ str,
70
+ Option(help="Thread ID for persistance", envvar="URSA_THREAD_ID"),
71
+ ] = "ursa_cli",
72
+ safe_codes: Annotated[
73
+ list[str],
74
+ Option(
75
+ help="Programming languages that the execution agent can trust by default.",
76
+ envvar="URSA_THREAD_ID",
77
+ ),
78
+ ] = ["python", "julia"],
79
+ arxiv_summarize: Annotated[
80
+ bool,
81
+ Option(
82
+ help="Whether or not to allow ArxivAgent to summarize response."
83
+ ),
84
+ ] = True,
85
+ arxiv_process_images: Annotated[
86
+ bool,
87
+ Option(help="Whether or not to allow ArxivAgent to process images."),
88
+ ] = False,
89
+ arxiv_max_results: Annotated[
90
+ int,
91
+ Option(
92
+ help="Maximum number of results for ArxivAgent to retrieve from ArXiv."
93
+ ),
94
+ ] = 10,
95
+ arxiv_database_path: Annotated[
96
+ Optional[Path],
97
+ Option(
98
+ help="Path to download/downloaded ArXiv documents; used by ArxivAgent."
99
+ ),
100
+ ] = None,
101
+ arxiv_summaries_path: Annotated[
102
+ Optional[Path],
103
+ Option(help="Path to store ArXiv paper summaries; used by ArxivAgent."),
104
+ ] = None,
105
+ arxiv_vectorstore_path: Annotated[
106
+ Optional[Path],
107
+ Option(
108
+ help="Path to store ArXiv paper vector store; used by ArxivAgent."
109
+ ),
110
+ ] = None,
111
+ arxiv_download_papers: Annotated[
112
+ bool,
113
+ Option(
114
+ help="Whether or not to allow ArxivAgent to download ArXiv papers."
115
+ ),
116
+ ] = True,
117
+ ssl_verify_llm: Annotated[
118
+ bool, Option(help="Whether or not to verify SSL certificates for LLM.")
119
+ ] = True,
120
+ ssl_verify_emb: Annotated[
121
+ bool,
122
+ Option(
123
+ help="Whether or not to verify SSL certificates for embedding model."
124
+ ),
125
+ ] = True,
126
+ ) -> None:
127
+ console = Console()
128
+ with console.status("[grey50]Loading ursa ..."):
129
+ from ursa.cli.hitl import HITL, UrsaRepl
130
+
131
+ hitl = HITL(
132
+ workspace=workspace,
133
+ llm_model_name=llm_model_name,
134
+ llm_base_url=llm_base_url,
135
+ llm_api_key=llm_api_key,
136
+ max_completion_tokens=max_completion_tokens,
137
+ emb_model_name=emb_model_name,
138
+ emb_base_url=emb_base_url,
139
+ emb_api_key=emb_api_key,
140
+ share_key=share_key,
141
+ thread_id=thread_id,
142
+ safe_codes=safe_codes,
143
+ arxiv_summarize=arxiv_summarize,
144
+ arxiv_process_images=arxiv_process_images,
145
+ arxiv_max_results=arxiv_max_results,
146
+ arxiv_database_path=arxiv_database_path,
147
+ arxiv_summaries_path=arxiv_summaries_path,
148
+ arxiv_vectorstore_path=arxiv_vectorstore_path,
149
+ arxiv_download_papers=arxiv_download_papers,
150
+ ssl_verify_llm=ssl_verify_llm,
151
+ ssl_verify_emb=ssl_verify_emb,
152
+ )
153
+ UrsaRepl(hitl).run()
154
+
155
+
156
+ @app.command()
157
+ def version() -> None:
158
+ from ursa import __version__
159
+
160
+ print(__version__)
161
+
162
+
163
+ @app.command(help="Start MCP server to serve ursa agents")
164
+ def serve(
165
+ host: Annotated[
166
+ str,
167
+ Option("--host", help="Bind address.", envvar="URSA_HOST"),
168
+ ] = "127.0.0.1",
169
+ port: Annotated[
170
+ int,
171
+ Option("--port", "-p", help="Bind port.", envvar="URSA_PORT"),
172
+ ] = 8000,
173
+ reload: Annotated[
174
+ bool,
175
+ Option("--reload/--no-reload", help="Auto-reload on code changes."),
176
+ ] = False,
177
+ log_level: Annotated[
178
+ str,
179
+ Option(
180
+ "--log-level",
181
+ "-l",
182
+ help="Uvicorn log level: critical|error|warning|info|debug|trace",
183
+ envvar="URSA_LOG_LEVEL",
184
+ ),
185
+ ] = "info",
186
+ workspace: Annotated[
187
+ Path, Option(help="Directory to store ursa ouput")
188
+ ] = Path("ursa_mcp"),
189
+ llm_model_name: Annotated[
190
+ str,
191
+ Option(
192
+ help=(
193
+ "Model provider and name of LLM to use for agent tasks. "
194
+ "Use format <provider>:<model-name>. "
195
+ "For example 'openai:gpt-5'. "
196
+ "See https://reference.langchain.com/python/langchain/models/?h=init_chat_model#langchain.chat_models.init_chat_model"
197
+ ),
198
+ ),
199
+ ] = "openai:gpt-5",
200
+ llm_base_url: Annotated[
201
+ Optional[str],
202
+ Option(help="Base url for LLM.", envvar="URSA_LLM_BASE_URL"),
203
+ ] = None,
204
+ llm_api_key: Annotated[
205
+ Optional[str],
206
+ Option(help="API key for LLM", envvar="URSA_LLM_API_KEY"),
207
+ ] = None,
208
+ max_completion_tokens: Annotated[
209
+ int, Option(help="Maximum tokens for LLM to output")
210
+ ] = 50000,
211
+ emb_model_name: Annotated[
212
+ Optional[str],
213
+ Option(
214
+ help=(
215
+ "Model provider and Embedding model name. "
216
+ "Use format <provider>:<embedding-model-name>. "
217
+ "For example, 'openai:text-embedding-3-small'. "
218
+ "See: https://reference.langchain.com/python/langchain/embeddings/?h=init_embeddings#langchain.embeddings.init_embeddings"
219
+ ),
220
+ envvar="URSA_EMB_NAME",
221
+ ),
222
+ ] = None,
223
+ emb_base_url: Annotated[
224
+ Optional[str],
225
+ Option(help="Base url for embedding model", envvar="URSA_EMB_BASE_URL"),
226
+ ] = None,
227
+ emb_api_key: Annotated[
228
+ Optional[str],
229
+ Option(help="API key for embedding model", envvar="URSA_EMB_API_KEY"),
230
+ ] = None,
231
+ share_key: Annotated[
232
+ bool,
233
+ Option(
234
+ help=(
235
+ "Whether or not the LLM and embedding model share the same "
236
+ "API key. If yes, then you can specify only one of them."
237
+ )
238
+ ),
239
+ ] = False,
240
+ thread_id: Annotated[
241
+ str,
242
+ Option(help="Thread ID for persistance", envvar="URSA_THREAD_ID"),
243
+ ] = "ursa_mcp",
244
+ safe_codes: Annotated[
245
+ list[str],
246
+ Option(
247
+ help="Programming languages that the execution agent can trust by default.",
248
+ envvar="URSA_THREAD_ID",
249
+ ),
250
+ ] = ["python", "julia"],
251
+ arxiv_summarize: Annotated[
252
+ bool,
253
+ Option(
254
+ help="Whether or not to allow ArxivAgent to summarize response."
255
+ ),
256
+ ] = True,
257
+ arxiv_process_images: Annotated[
258
+ bool,
259
+ Option(help="Whether or not to allow ArxivAgent to process images."),
260
+ ] = False,
261
+ arxiv_max_results: Annotated[
262
+ int,
263
+ Option(
264
+ help="Maximum number of results for ArxivAgent to retrieve from ArXiv."
265
+ ),
266
+ ] = 10,
267
+ arxiv_database_path: Annotated[
268
+ Optional[Path],
269
+ Option(
270
+ help="Path to download/downloaded ArXiv documents; used by ArxivAgent."
271
+ ),
272
+ ] = None,
273
+ arxiv_summaries_path: Annotated[
274
+ Optional[Path],
275
+ Option(help="Path to store ArXiv paper summaries; used by ArxivAgent."),
276
+ ] = None,
277
+ arxiv_vectorstore_path: Annotated[
278
+ Optional[Path],
279
+ Option(
280
+ help="Path to store ArXiv paper vector store; used by ArxivAgent."
281
+ ),
282
+ ] = None,
283
+ arxiv_download_papers: Annotated[
284
+ bool,
285
+ Option(
286
+ help="Whether or not to allow ArxivAgent to download ArXiv papers."
287
+ ),
288
+ ] = True,
289
+ ssl_verify_llm: Annotated[
290
+ bool, Option(help="Whether or not to verify SSL certificates for LLM.")
291
+ ] = True,
292
+ ssl_verify_emb: Annotated[
293
+ bool,
294
+ Option(
295
+ help="Whether or not to verify SSL certificates for embedding model."
296
+ ),
297
+ ] = True,
298
+ ) -> None:
299
+ console = Console()
300
+ with console.status("[grey50]Starting ursa MCP server ..."):
301
+ from ursa.cli.hitl import HITL
302
+
303
+ app_path = "ursa.cli.hitl_api:mcp_app"
304
+
305
+ try:
306
+ import uvicorn
307
+ except Exception as e:
308
+ secho(
309
+ f"Uvicorn is required for 'ursa serve'. Install with: pip install uvicorn[standard]\n{e}",
310
+ fg=colors.RED,
311
+ )
312
+ raise Exit(code=1)
313
+
314
+ hitl = HITL(
315
+ workspace=workspace,
316
+ llm_model_name=llm_model_name,
317
+ llm_base_url=llm_base_url,
318
+ llm_api_key=llm_api_key,
319
+ max_completion_tokens=max_completion_tokens,
320
+ emb_model_name=emb_model_name,
321
+ emb_base_url=emb_base_url,
322
+ emb_api_key=emb_api_key,
323
+ share_key=share_key,
324
+ thread_id=thread_id,
325
+ safe_codes=safe_codes,
326
+ arxiv_summarize=arxiv_summarize,
327
+ arxiv_process_images=arxiv_process_images,
328
+ arxiv_max_results=arxiv_max_results,
329
+ arxiv_database_path=arxiv_database_path,
330
+ arxiv_summaries_path=arxiv_summaries_path,
331
+ arxiv_vectorstore_path=arxiv_vectorstore_path,
332
+ arxiv_download_papers=arxiv_download_papers,
333
+ ssl_verify_llm=ssl_verify_llm,
334
+ ssl_verify_emb=ssl_verify_emb,
335
+ )
336
+ module_name, var_name = app_path.split(":")
337
+ mod = importlib.import_module(module_name)
338
+ asgi_app = getattr(mod, var_name)
339
+ asgi_app.state.hitl = hitl
340
+
341
+ config = uvicorn.Config(
342
+ app=asgi_app,
343
+ host=host,
344
+ port=port,
345
+ reload=reload,
346
+ workers=1,
347
+ log_level=log_level.lower(),
348
+ )
349
+
350
+ server = uvicorn.Server(config)
351
+ console.print(
352
+ f"[bold]URSA MCP server[/bold] starting at "
353
+ f"http://{host}:{port} "
354
+ f"(app: {app_path})"
355
+ )
356
+ try:
357
+ server.run()
358
+ except KeyboardInterrupt:
359
+ console.print("[grey50]Shutting down...[/grey50]")
360
+
361
+
362
+ def main():
363
+ app()