roscoe 0.1.0__tar.gz

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 (112) hide show
  1. roscoe-0.1.0/LICENSE +21 -0
  2. roscoe-0.1.0/PKG-INFO +477 -0
  3. roscoe-0.1.0/README.md +442 -0
  4. roscoe-0.1.0/pyproject.toml +67 -0
  5. roscoe-0.1.0/roscoe/__init__.py +8 -0
  6. roscoe-0.1.0/roscoe/approval/__init__.py +5 -0
  7. roscoe-0.1.0/roscoe/approval/gate.py +73 -0
  8. roscoe-0.1.0/roscoe/cli/__init__.py +5 -0
  9. roscoe-0.1.0/roscoe/cli/eval_command.py +79 -0
  10. roscoe-0.1.0/roscoe/cli/init_command.py +486 -0
  11. roscoe-0.1.0/roscoe/cli/main.py +25 -0
  12. roscoe-0.1.0/roscoe/cli/monitor_command.py +29 -0
  13. roscoe-0.1.0/roscoe/cli/scaffold/.env.example +43 -0
  14. roscoe-0.1.0/roscoe/cli/scaffold/agent_config.yaml +176 -0
  15. roscoe-0.1.0/roscoe/cli/scaffold/docs.md +659 -0
  16. roscoe-0.1.0/roscoe/cli/scaffold/evals/test_cases.json +37 -0
  17. roscoe-0.1.0/roscoe/cli/scaffold/main.py +42 -0
  18. roscoe-0.1.0/roscoe/cli/scaffold/prompts/system.txt +26 -0
  19. roscoe-0.1.0/roscoe/cli/scaffold/tools/my_tools.py +60 -0
  20. roscoe-0.1.0/roscoe/cli/wizard_gui.py +343 -0
  21. roscoe-0.1.0/roscoe/config/__init__.py +0 -0
  22. roscoe-0.1.0/roscoe/config/loader.py +76 -0
  23. roscoe-0.1.0/roscoe/connectors/__init__.py +30 -0
  24. roscoe-0.1.0/roscoe/connectors/_graph_base.py +63 -0
  25. roscoe-0.1.0/roscoe/connectors/base_connector.py +59 -0
  26. roscoe-0.1.0/roscoe/connectors/github.py +79 -0
  27. roscoe-0.1.0/roscoe/connectors/google_workspace.py +229 -0
  28. roscoe-0.1.0/roscoe/connectors/jira.py +103 -0
  29. roscoe-0.1.0/roscoe/connectors/notion.py +87 -0
  30. roscoe-0.1.0/roscoe/connectors/outlook.py +90 -0
  31. roscoe-0.1.0/roscoe/connectors/rest_api.py +71 -0
  32. roscoe-0.1.0/roscoe/connectors/servicenow.py +93 -0
  33. roscoe-0.1.0/roscoe/connectors/sharepoint.py +66 -0
  34. roscoe-0.1.0/roscoe/connectors/snowflake.py +93 -0
  35. roscoe-0.1.0/roscoe/core/__init__.py +8 -0
  36. roscoe-0.1.0/roscoe/core/agent_base.py +32 -0
  37. roscoe-0.1.0/roscoe/core/agent_result.py +37 -0
  38. roscoe-0.1.0/roscoe/core/agent_runner.py +375 -0
  39. roscoe-0.1.0/roscoe/core/executor.py +124 -0
  40. roscoe-0.1.0/roscoe/core/state.py +18 -0
  41. roscoe-0.1.0/roscoe/evals/__init__.py +34 -0
  42. roscoe-0.1.0/roscoe/evals/dataset.py +61 -0
  43. roscoe-0.1.0/roscoe/evals/eval_runner.py +86 -0
  44. roscoe-0.1.0/roscoe/evals/regression.py +54 -0
  45. roscoe-0.1.0/roscoe/evals/report.py +47 -0
  46. roscoe-0.1.0/roscoe/evals/scorers/__init__.py +15 -0
  47. roscoe-0.1.0/roscoe/evals/scorers/_judge.py +31 -0
  48. roscoe-0.1.0/roscoe/evals/scorers/base.py +43 -0
  49. roscoe-0.1.0/roscoe/evals/scorers/hallucination.py +44 -0
  50. roscoe-0.1.0/roscoe/evals/scorers/output_quality.py +42 -0
  51. roscoe-0.1.0/roscoe/evals/scorers/tool_usage.py +40 -0
  52. roscoe-0.1.0/roscoe/llm/__init__.py +7 -0
  53. roscoe-0.1.0/roscoe/llm/base_provider.py +33 -0
  54. roscoe-0.1.0/roscoe/llm/capability_map.py +53 -0
  55. roscoe-0.1.0/roscoe/llm/provider_factory.py +160 -0
  56. roscoe-0.1.0/roscoe/memory/__init__.py +7 -0
  57. roscoe-0.1.0/roscoe/memory/conversation.py +34 -0
  58. roscoe-0.1.0/roscoe/memory/knowledge.py +100 -0
  59. roscoe-0.1.0/roscoe/memory/persistent.py +60 -0
  60. roscoe-0.1.0/roscoe/middleware/__init__.py +18 -0
  61. roscoe-0.1.0/roscoe/middleware/audit_logger.py +85 -0
  62. roscoe-0.1.0/roscoe/middleware/cost_tracker.py +70 -0
  63. roscoe-0.1.0/roscoe/middleware/rate_limiter.py +67 -0
  64. roscoe-0.1.0/roscoe/middleware/retry.py +95 -0
  65. roscoe-0.1.0/roscoe/monitoring/__init__.py +28 -0
  66. roscoe-0.1.0/roscoe/monitoring/alerts.py +65 -0
  67. roscoe-0.1.0/roscoe/monitoring/dashboard.py +41 -0
  68. roscoe-0.1.0/roscoe/monitoring/exporters/__init__.py +5 -0
  69. roscoe-0.1.0/roscoe/monitoring/exporters/azure_monitor.py +52 -0
  70. roscoe-0.1.0/roscoe/monitoring/exporters/prometheus.py +70 -0
  71. roscoe-0.1.0/roscoe/monitoring/metrics.py +148 -0
  72. roscoe-0.1.0/roscoe/monitoring/notifier.py +64 -0
  73. roscoe-0.1.0/roscoe/templates/__init__.py +35 -0
  74. roscoe-0.1.0/roscoe/templates/exec_assistant_agent/__init__.py +0 -0
  75. roscoe-0.1.0/roscoe/templates/exec_assistant_agent/agent_config.yaml +34 -0
  76. roscoe-0.1.0/roscoe/templates/exec_assistant_agent/prompts/system.txt +16 -0
  77. roscoe-0.1.0/roscoe/templates/exec_assistant_agent/tools/__init__.py +0 -0
  78. roscoe-0.1.0/roscoe/templates/exec_assistant_agent/tools/exec_tools.py +16 -0
  79. roscoe-0.1.0/roscoe/templates/google_workspace_agent/agent_config.yaml +32 -0
  80. roscoe-0.1.0/roscoe/templates/google_workspace_agent/prompts/system.txt +16 -0
  81. roscoe-0.1.0/roscoe/templates/google_workspace_agent/tools/__init__.py +0 -0
  82. roscoe-0.1.0/roscoe/templates/google_workspace_agent/tools/gws_tools.py +16 -0
  83. roscoe-0.1.0/roscoe/templates/hr_agent/__init__.py +0 -0
  84. roscoe-0.1.0/roscoe/templates/hr_agent/agent_config.yaml +37 -0
  85. roscoe-0.1.0/roscoe/templates/hr_agent/prompts/system.txt +13 -0
  86. roscoe-0.1.0/roscoe/templates/hr_agent/tools/__init__.py +0 -0
  87. roscoe-0.1.0/roscoe/templates/hr_agent/tools/hr_tools.py +68 -0
  88. roscoe-0.1.0/roscoe/templates/it_support_agent/__init__.py +0 -0
  89. roscoe-0.1.0/roscoe/templates/it_support_agent/agent_config.yaml +32 -0
  90. roscoe-0.1.0/roscoe/templates/it_support_agent/prompts/system.txt +15 -0
  91. roscoe-0.1.0/roscoe/templates/it_support_agent/tools/__init__.py +0 -0
  92. roscoe-0.1.0/roscoe/templates/it_support_agent/tools/it_tools.py +66 -0
  93. roscoe-0.1.0/roscoe/templates/knowledge_base_agent/__init__.py +0 -0
  94. roscoe-0.1.0/roscoe/templates/knowledge_base_agent/agent_config.yaml +34 -0
  95. roscoe-0.1.0/roscoe/templates/knowledge_base_agent/prompts/system.txt +11 -0
  96. roscoe-0.1.0/roscoe/templates/knowledge_base_agent/tools/__init__.py +0 -0
  97. roscoe-0.1.0/roscoe/templates/knowledge_base_agent/tools/kb_tools.py +49 -0
  98. roscoe-0.1.0/roscoe/templates/legal_agent/__init__.py +0 -0
  99. roscoe-0.1.0/roscoe/templates/legal_agent/agent_config.yaml +26 -0
  100. roscoe-0.1.0/roscoe/templates/legal_agent/prompts/system.txt +12 -0
  101. roscoe-0.1.0/roscoe/templates/legal_agent/tools/__init__.py +0 -0
  102. roscoe-0.1.0/roscoe/templates/legal_agent/tools/legal_tools.py +68 -0
  103. roscoe-0.1.0/roscoe/tools/__init__.py +5 -0
  104. roscoe-0.1.0/roscoe/tools/decorator.py +59 -0
  105. roscoe-0.1.0/roscoe.egg-info/PKG-INFO +477 -0
  106. roscoe-0.1.0/roscoe.egg-info/SOURCES.txt +110 -0
  107. roscoe-0.1.0/roscoe.egg-info/dependency_links.txt +1 -0
  108. roscoe-0.1.0/roscoe.egg-info/entry_points.txt +2 -0
  109. roscoe-0.1.0/roscoe.egg-info/requires.txt +19 -0
  110. roscoe-0.1.0/roscoe.egg-info/top_level.txt +1 -0
  111. roscoe-0.1.0/setup.cfg +4 -0
  112. roscoe-0.1.0/tests/test_smoke.py +14 -0
roscoe-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 rhealaloo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
roscoe-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,477 @@
1
+ Metadata-Version: 2.4
2
+ Name: roscoe
3
+ Version: 0.1.0
4
+ Summary: Provider-agnostic LangChain agent framework with middleware and evals.
5
+ Author-email: rhealaloo <rhealaloo@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/rhealaloo45/roscoe
8
+ Project-URL: Repository, https://github.com/rhealaloo45/roscoe
9
+ Project-URL: Issues, https://github.com/rhealaloo45/roscoe/issues
10
+ Keywords: langchain,agents,llm,sdk,react
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: langchain==0.3.25
19
+ Requires-Dist: langchain-openai<0.4,>=0.2
20
+ Requires-Dist: langchain-google-genai<3.0,>=2.0
21
+ Requires-Dist: langchain-anthropic<0.4,>=0.3
22
+ Requires-Dist: langchain-ollama<0.4,>=0.2
23
+ Requires-Dist: pydantic<3.0,>=2.10
24
+ Requires-Dist: pyyaml<7.0,>=6.0
25
+ Requires-Dist: click<9.0,>=8.1
26
+ Requires-Dist: httpx<1.0,>=0.27
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest<9.0,>=8.0; extra == "dev"
29
+ Requires-Dist: pytest-asyncio<1.0,>=0.24; extra == "dev"
30
+ Provides-Extra: snowflake
31
+ Requires-Dist: snowflake-connector-python<4.0,>=3.0; extra == "snowflake"
32
+ Provides-Extra: azure
33
+ Requires-Dist: azure-monitor-opentelemetry<2.0,>=1.0; extra == "azure"
34
+ Dynamic: license-file
35
+
36
+ # roscoe
37
+
38
+ > Provider-agnostic AI agent SDK — production-ready from line one.
39
+
40
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
41
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org)
42
+
43
+ **roscoe** is a Python SDK for building LLM-powered agents that ship with production
44
+ plumbing built in — retries, cost tracking, audit logging, rate limiting, human approval,
45
+ memory, monitoring, and evals. You write tools (plain Python functions) and a YAML config;
46
+ roscoe handles everything else.
47
+
48
+ Switch LLM providers by editing one config block. Your code never changes.
49
+
50
+ ```
51
+ pip install roscoe
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Quick start
57
+
58
+ ### Option A: Scaffold with the CLI
59
+
60
+ ```bash
61
+ roscoe init my-agent
62
+ ```
63
+
64
+ A GUI wizard opens — pick your provider, toggle middleware, configure memory. Hit
65
+ **Create Project** and you get a ready-to-run folder:
66
+
67
+ ```
68
+ my-agent/
69
+ ├── agent_config.yaml # fully commented — every option explained
70
+ ├── main.py # 6 lines to run your agent
71
+ ├── tools/my_tools.py # your @tool functions go here
72
+ ├── prompts/system.txt # agent personality + instructions
73
+ ├── evals/test_cases.json
74
+ └── .env.example # all possible credential placeholders
75
+ ```
76
+
77
+ ```bash
78
+ cd my-agent
79
+ cp .env.example .env # fill in your API key
80
+ python main.py
81
+ ```
82
+
83
+ Use `--quick` to skip the wizard, or `--cli` for a terminal-based wizard.
84
+
85
+ ### Option B: Code it directly
86
+
87
+ ```python
88
+ from roscoe import AgentRunner
89
+ from roscoe.tools import tool
90
+
91
+
92
+ @tool
93
+ def get_price(sku: str) -> dict:
94
+ """Fetch the price for a product SKU."""
95
+ return {"sku": sku, "price": 1999}
96
+
97
+
98
+ agent = AgentRunner.from_config("agent_config.yaml", tools=[get_price])
99
+ result = agent.run("What is the price of SKU-001?")
100
+
101
+ print(result.output) # the LLM's answer
102
+ print(result.status) # "success" | "error" | "paused"
103
+ print(result.cost_usd) # estimated cost in USD
104
+ print(result.total_tokens) # token usage
105
+ print(result.run_id) # UUID tying this run to the audit trail
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Features
111
+
112
+ ### Provider-agnostic
113
+
114
+ Swap LLM providers by editing the `model:` block in your YAML config. Your Python code
115
+ stays identical.
116
+
117
+ | Provider | Config key | Example model |
118
+ |---|---|---|
119
+ | OpenAI | `openai` | `gpt-4o-mini` |
120
+ | OpenRouter | `openai` + `base_url` | any of 100+ models |
121
+ | Azure OpenAI | `azure_openai` | `gpt-4o` (via deployment) |
122
+ | Anthropic | `anthropic` | `claude-sonnet-4-5` |
123
+ | Google Gemini | `gemini` | `gemini-1.5-pro` |
124
+ | Ollama (local) | `ollama` | `llama3.1` (free, no key) |
125
+
126
+ Register custom providers: `ProviderFactory.register("my_provider", MyProviderClass)`.
127
+
128
+ ```yaml
129
+ # Just change this block — nothing else
130
+ model:
131
+ provider: openai
132
+ model: gpt-4o-mini
133
+ api_key: ${OPENAI_API_KEY}
134
+ temperature: 0.1
135
+ ```
136
+
137
+ ### Automatic middleware
138
+
139
+ All middleware is configured in YAML and runs automatically on every `agent.run()` call.
140
+ Zero boilerplate code.
141
+
142
+ ```yaml
143
+ middleware:
144
+ retry:
145
+ max_attempts: 3 # exponential backoff on transient errors
146
+ rate_limiter:
147
+ enabled: true
148
+ requests_per_minute: 60 # token-bucket per provider
149
+ cost_tracking:
150
+ enabled: true # USD estimate in result.cost_usd
151
+ audit:
152
+ enabled: true # JSONL log at logs/audit.jsonl
153
+ ```
154
+
155
+ - **Retry** — handles rate limits, timeouts, 500s with exponential backoff.
156
+ - **Rate limiting** — token-bucket algorithm, one bucket per provider. Prevents thrashing
157
+ API limits when multiple agents share a provider. Ollama is skipped (no external limit).
158
+ - **Cost tracking** — reads `usage_metadata` from LangChain, prices via built-in rate
159
+ table. Extensible:
160
+ ```python
161
+ from roscoe.middleware.cost_tracker import COST_TABLE
162
+ COST_TABLE["openai"]["gpt-4.1"] = {"input": 0.002, "output": 0.008}
163
+ ```
164
+ - **Audit logging** — non-blocking JSONL, one line per run: run_id, agent, provider,
165
+ model, tokens, cost, status, latency. Feed to `roscoe monitor` for dashboards.
166
+
167
+ ### Memory
168
+
169
+ Three types, all configured in YAML:
170
+
171
+ ```yaml
172
+ memory:
173
+ conversation:
174
+ enabled: true
175
+ window_size: 10 # last N messages per session_id
176
+ persistent:
177
+ enabled: true
178
+ backend: sqlite
179
+ connection: ./facts.db # long-term facts per user_id
180
+ ```
181
+
182
+ - **Conversation** — short-term, per `session_id`, windowed. Pass `session_id` to
183
+ `agent.run()` to keep context across turns.
184
+ - **Persistent** — long-term facts per `user_id` in sqlite. The agent remembers "My name
185
+ is Rhea" across sessions.
186
+ - **Knowledge / RAG** — vector retrieval via FAISS (if installed) or a zero-dependency
187
+ keyword retriever. Set up in code:
188
+ ```python
189
+ from roscoe.memory.knowledge import KnowledgeMemory
190
+ km = KnowledgeMemory.from_texts(["policy doc text..."], metadatas=[{"source": "hr.pdf"}])
191
+ ```
192
+
193
+ ### Connectors
194
+
195
+ Pre-built tool bundles for enterprise systems. Each connector gives you LangChain tools
196
+ you hand straight to `AgentRunner`:
197
+
198
+ ```python
199
+ from roscoe.connectors import GitHubConnector
200
+
201
+ gh = GitHubConnector({"token": "ghp_..."})
202
+ agent = AgentRunner.from_config("agent.yaml", tools=gh.tools)
203
+
204
+ # Mix with your own tools:
205
+ agent = AgentRunner.from_config("agent.yaml", tools=[my_tool] + gh.tools)
206
+ ```
207
+
208
+ | Connector | Tools | Auth |
209
+ |---|---|---|
210
+ | **REST** (any API) | GET, POST, PUT, DELETE | Bearer / Basic / API key |
211
+ | **Jira** | search, create, update, transition issues | Email + API token |
212
+ | **ServiceNow** | create, query, update incidents | Username + password |
213
+ | **Outlook** | send email, read inbox, create event, availability | MS Graph (OAuth2) |
214
+ | **SharePoint** | list files, download, upload, search | MS Graph (OAuth2) |
215
+ | **GitHub** | list repos, issues, PRs, create issue | Personal access token |
216
+ | **Notion** | search, pages, databases, blocks | Integration token |
217
+ | **Google Workspace** | Gmail send/read, Calendar, Tasks, Drive search | Service account |
218
+ | **Snowflake** | execute SQL queries | `pip install roscoe[snowflake]` |
219
+
220
+ ### Human-in-the-loop
221
+
222
+ Make sensitive tools require approval before they run:
223
+
224
+ ```yaml
225
+ middleware:
226
+ human_approval:
227
+ require_approval_for: ["send_email", "delete_record"]
228
+ ```
229
+
230
+ ```python
231
+ result = agent.run("Send an email to bob@acme.com")
232
+
233
+ if result.status == "paused":
234
+ print(result.pending_action) # inspect what the agent wants to do
235
+
236
+ # approve — tool runs as planned
237
+ result = agent.resume(result.run_id, "approve")
238
+
239
+ # reject — tool is blocked, agent gets a rejection message
240
+ result = agent.resume(result.run_id, "reject")
241
+
242
+ # modify — change the arguments before running
243
+ result = agent.resume(result.run_id, "modify", payload={"to": "correct@acme.com"})
244
+ ```
245
+
246
+ The run stops *before* the gated tool executes and returns `status="paused"`. Call
247
+ `resume()` to continue. Wire this to a Slack button, a web UI, or a CLI prompt.
248
+
249
+ ### Monitoring
250
+
251
+ Offline aggregation of your audit logs — no live server required.
252
+
253
+ ```bash
254
+ roscoe monitor --path logs/audit.jsonl
255
+ ```
256
+
257
+ Outputs a text dashboard with:
258
+ - Total runs, cost per day, cost per agent
259
+ - Latency percentiles (p50 / p95 / p99) per agent
260
+ - Error rate breakdown
261
+ - Token usage summary
262
+
263
+ **Alerts** — configure thresholds for daily cost, error rate, and latency:
264
+
265
+ ```python
266
+ from roscoe.monitoring.alerts import check_and_notify
267
+ from roscoe.monitoring.notifier import build_notifier
268
+
269
+ notifier = build_notifier("slack", {"webhook_url": "https://hooks.slack.com/..."})
270
+ check_and_notify(metrics, alert_config, notifier)
271
+ ```
272
+
273
+ **Exporters** — push metrics to Prometheus Pushgateway or Azure Monitor:
274
+
275
+ ```python
276
+ from roscoe.monitoring.exporters.prometheus import PrometheusPushgatewayExporter
277
+ exporter = PrometheusPushgatewayExporter(gateway_url="http://localhost:9091")
278
+ exporter.push(metrics)
279
+ ```
280
+
281
+ ### Evals
282
+
283
+ Test your agent with a dataset of cases and score the results:
284
+
285
+ ```bash
286
+ roscoe eval --dataset evals/test_cases.json --config agent_config.yaml
287
+ ```
288
+
289
+ **Scorers:**
290
+ - **Tool usage** — deterministic, order-aware (did the agent call the right tools?).
291
+ - **Output quality** — LLM-as-judge, 0–10 scale. Add `--judge` to enable.
292
+ - **Hallucination** — LLM-as-judge, checks output against provided context docs.
293
+
294
+ **Regression diffing** — compare two eval runs:
295
+
296
+ ```python
297
+ from roscoe.evals.regression import compare_runs
298
+ diff = compare_runs(report_a, report_b)
299
+ print(diff.improved) # cases that got better
300
+ print(diff.regressed) # cases that got worse
301
+ ```
302
+
303
+ **Test case format** (`evals/test_cases.json`):
304
+
305
+ ```json
306
+ {
307
+ "cases": [
308
+ {
309
+ "id": "weather-london",
310
+ "input": "What's the weather in London?",
311
+ "expected_tools": ["get_weather"],
312
+ "expected_output": "Should mention London weather",
313
+ "context_docs": ["London is currently 15°C and rainy."]
314
+ }
315
+ ]
316
+ }
317
+ ```
318
+
319
+ ### Templates
320
+
321
+ Six pre-built templates, each with tools, system prompt, config, and approval gates
322
+ pre-configured:
323
+
324
+ ```bash
325
+ roscoe init my-hr-bot --template hr_agent
326
+ roscoe init my-it-bot --template it_support_agent
327
+ roscoe init my-legal --template legal_agent
328
+ roscoe init my-kb --template knowledge_base_agent
329
+ roscoe init my-ea --template exec_assistant_agent
330
+ roscoe init my-gws --template google_workspace_agent
331
+ ```
332
+
333
+ | Template | Use case | Connector | Approval gate |
334
+ |---|---|---|---|
335
+ | `hr_agent` | Leave, payslips, personal details | REST API | submit_leave_request |
336
+ | `it_support_agent` | Tickets, escalation, KB search | ServiceNow | escalate_ticket |
337
+ | `legal_agent` | Contract search, clause extraction, risk flags | Knowledge (RAG) | — |
338
+ | `knowledge_base_agent` | Q&A over Notion / SharePoint / docs | Notion + Knowledge | — (read-only) |
339
+ | `exec_assistant_agent` | Email, calendar, availability | Outlook (MS Graph) | send_email, create_event |
340
+ | `google_workspace_agent` | Gmail, Calendar, Tasks, Drive | Google Workspace | send_email, create_event, create_task |
341
+
342
+ ---
343
+
344
+ ## Architecture
345
+
346
+ roscoe runs its own async ReAct loop (no LangGraph dependency). The loop is ~100 lines
347
+ in `roscoe/core/executor.py`:
348
+
349
+ ```
350
+ User message
351
+ → model.invoke(messages)
352
+ → tool_calls in response?
353
+ → approval gate check (pause if gated)
354
+ → execute tools
355
+ → append results to messages
356
+ → loop back to model
357
+ → no tool_calls? done → AgentResult
358
+ ```
359
+
360
+ Built on **LangChain** (models, tools, messages) but not LangGraph. This keeps the agent
361
+ loop small, transparent, and easy to debug.
362
+
363
+ ---
364
+
365
+ ## CLI reference
366
+
367
+ ```bash
368
+ roscoe init <name> # scaffold with GUI wizard
369
+ roscoe init <name> --quick # scaffold with defaults (no wizard)
370
+ roscoe init <name> --cli # scaffold with terminal wizard
371
+ roscoe init <name> --template <t> # scaffold from a template
372
+
373
+ roscoe monitor # dashboard from logs/audit.jsonl
374
+ roscoe monitor --path /path/to/audit.jsonl # custom audit log path
375
+
376
+ roscoe eval --dataset cases.json --config agent.yaml # tool-usage scoring
377
+ roscoe eval --dataset cases.json --config agent.yaml --judge # + LLM-as-judge
378
+ roscoe eval --dataset cases.json --config agent.yaml --tools module:attr # custom tools
379
+
380
+ roscoe --version # print version
381
+ ```
382
+
383
+ ---
384
+
385
+ ## Install
386
+
387
+ ```bash
388
+ pip install roscoe # core
389
+ pip install "roscoe[snowflake]" # + Snowflake driver
390
+ pip install "roscoe[azure]" # + Azure Monitor exporter
391
+ pip install "roscoe[dev]" # + pytest (for contributors)
392
+ ```
393
+
394
+ ### From source
395
+
396
+ ```bash
397
+ git clone https://github.com/rhealaloo45/roscoe.git
398
+ cd roscoe
399
+ pip install -e ".[dev]"
400
+ pytest -q # 121 tests, all passing
401
+ ```
402
+
403
+ ---
404
+
405
+ ## Writing tools
406
+
407
+ A tool is a plain Python function with type hints and a docstring:
408
+
409
+ ```python
410
+ from roscoe.tools import tool
411
+
412
+
413
+ @tool
414
+ def search_docs(query: str) -> list[dict]:
415
+ """Search internal documents. Use when the user asks about company policies."""
416
+ # your logic here
417
+ return [{"title": "Remote Work Policy", "snippet": "..."}]
418
+ ```
419
+
420
+ - The **docstring** is what the LLM reads to decide when to call the tool.
421
+ - **Type hints** are used to generate the JSON schema automatically.
422
+ - **Return dicts or primitives** — the LLM reads the return value.
423
+ - Add the tool to the `TOOLS` list in `tools/my_tools.py`, or pass it directly to
424
+ `AgentRunner.from_config()`.
425
+
426
+ ---
427
+
428
+ ## Configuration reference
429
+
430
+ Full `agent_config.yaml` with all options (also generated by `roscoe init` with inline
431
+ comments):
432
+
433
+ ```yaml
434
+ agent_name: my-agent
435
+
436
+ system_prompt_file: prompts/system.txt
437
+ # system_prompt: |
438
+ # Inline prompt alternative
439
+
440
+ model:
441
+ provider: openai # openai | azure_openai | anthropic | gemini | ollama
442
+ model: gpt-4o-mini
443
+ api_key: ${OPENAI_API_KEY} # resolved from environment
444
+ temperature: 0.1
445
+ # base_url: https://openrouter.ai/api/v1 # for OpenRouter / custom endpoints
446
+ # max_tokens: 4096
447
+
448
+ memory:
449
+ conversation:
450
+ enabled: true
451
+ window_size: 10
452
+ persistent:
453
+ enabled: false
454
+ backend: sqlite
455
+ connection: ./facts.db
456
+
457
+ middleware:
458
+ retry:
459
+ max_attempts: 3
460
+ rate_limiter:
461
+ enabled: true
462
+ requests_per_minute: 60
463
+ cost_tracking:
464
+ enabled: true
465
+ audit:
466
+ enabled: true
467
+ # human_approval:
468
+ # require_approval_for: ["send_email", "delete_record"]
469
+ ```
470
+
471
+ Environment variables use `${VAR_NAME}` syntax and are resolved at config load time.
472
+
473
+ ---
474
+
475
+ ## License
476
+
477
+ MIT — see [LICENSE](./LICENSE).