agent-framework-devui 0.0.1a0__tar.gz → 1.0.0b251001__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.
Potentially problematic release.
This version of agent-framework-devui might be problematic. Click here for more details.
- agent_framework_devui-1.0.0b251001/.gitignore +19 -0
- agent_framework_devui-1.0.0b251001/LICENSE +21 -0
- agent_framework_devui-1.0.0b251001/PKG-INFO +172 -0
- agent_framework_devui-1.0.0b251001/README.md +139 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/__init__.py +151 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/_cli.py +143 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/_discovery.py +724 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/_executor.py +770 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/_mapper.py +582 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/_server.py +530 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/_session.py +191 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/_tracing.py +168 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/models/__init__.py +72 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/models/_discovery_models.py +51 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/models/_openai_custom.py +209 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/ui/assets/index-D1AmQWga.css +1 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/ui/assets/index-DPEaaIdK.js +435 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/ui/index.html +14 -0
- agent_framework_devui-1.0.0b251001/agent_framework_devui/ui/vite.svg +1 -0
- agent_framework_devui-1.0.0b251001/dev.md +111 -0
- agent_framework_devui-1.0.0b251001/docs/devuiscreen.png +0 -0
- agent_framework_devui-1.0.0b251001/frontend/.gitignore +23 -0
- agent_framework_devui-1.0.0b251001/frontend/README.md +69 -0
- agent_framework_devui-1.0.0b251001/frontend/components.json +21 -0
- agent_framework_devui-1.0.0b251001/frontend/eslint.config.js +23 -0
- agent_framework_devui-1.0.0b251001/frontend/index.html +13 -0
- agent_framework_devui-1.0.0b251001/frontend/package.json +46 -0
- agent_framework_devui-1.0.0b251001/frontend/public/vite.svg +1 -0
- agent_framework_devui-1.0.0b251001/frontend/src/App.css +42 -0
- agent_framework_devui-1.0.0b251001/frontend/src/App.tsx +470 -0
- agent_framework_devui-1.0.0b251001/frontend/src/assets/react.svg +1 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/agent/agent-view.tsx +1082 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/gallery/gallery-view.tsx +412 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/gallery/index.ts +5 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/message_renderer/ContentRenderer.tsx +331 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/message_renderer/MessageRenderer.tsx +38 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/message_renderer/StreamingRenderer.tsx +114 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/message_renderer/index.ts +8 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/message_renderer/types.ts +48 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/mode-toggle.tsx +39 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/shared/about-modal.tsx +55 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/shared/app-header.tsx +54 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/shared/debug-panel.tsx +1394 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/shared/entity-selector.tsx +258 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/shared/settings-modal.tsx +195 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/theme-provider.tsx +33 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/attachment-gallery.tsx +123 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/badge.tsx +36 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/button.tsx +59 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/card.tsx +92 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/checkbox.tsx +32 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/dialog.tsx +104 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/dropdown-menu.tsx +255 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/file-upload.tsx +141 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/input.tsx +21 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/label.tsx +22 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/loading-spinner.tsx +23 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/loading-state.tsx +52 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/scroll-area.tsx +46 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/select.tsx +183 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/tabs.tsx +53 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/ui/textarea.tsx +18 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/workflow/executor-node.tsx +235 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/workflow/workflow-flow.tsx +517 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/workflow/workflow-input-form.tsx +503 -0
- agent_framework_devui-1.0.0b251001/frontend/src/components/workflow/workflow-view.tsx +959 -0
- agent_framework_devui-1.0.0b251001/frontend/src/data/gallery/index.ts +5 -0
- agent_framework_devui-1.0.0b251001/frontend/src/data/gallery/sample-entities.ts +185 -0
- agent_framework_devui-1.0.0b251001/frontend/src/hooks/useWorkflowEventCorrelation.ts +126 -0
- agent_framework_devui-1.0.0b251001/frontend/src/index.css +147 -0
- agent_framework_devui-1.0.0b251001/frontend/src/main.tsx +18 -0
- agent_framework_devui-1.0.0b251001/frontend/src/services/api.ts +497 -0
- agent_framework_devui-1.0.0b251001/frontend/src/types/agent-framework.ts +319 -0
- agent_framework_devui-1.0.0b251001/frontend/src/types/index.ts +152 -0
- agent_framework_devui-1.0.0b251001/frontend/src/types/openai.ts +228 -0
- agent_framework_devui-1.0.0b251001/frontend/src/types/workflow.ts +159 -0
- agent_framework_devui-1.0.0b251001/frontend/src/utils/simple-layout.ts +139 -0
- agent_framework_devui-1.0.0b251001/frontend/src/utils/workflow-utils.ts +519 -0
- agent_framework_devui-1.0.0b251001/frontend/src/vite-env.d.ts +9 -0
- agent_framework_devui-1.0.0b251001/frontend/tsconfig.app.json +29 -0
- agent_framework_devui-1.0.0b251001/frontend/tsconfig.json +13 -0
- agent_framework_devui-1.0.0b251001/frontend/tsconfig.node.json +23 -0
- agent_framework_devui-1.0.0b251001/frontend/vite.config.ts +34 -0
- agent_framework_devui-1.0.0b251001/frontend/yarn.lock +2455 -0
- agent_framework_devui-1.0.0b251001/pyproject.toml +96 -0
- agent_framework_devui-1.0.0b251001/samples/__init__.py +3 -0
- agent_framework_devui-1.0.0b251001/samples/fanout_workflow/__init__.py +3 -0
- agent_framework_devui-1.0.0b251001/samples/fanout_workflow/workflow.py +700 -0
- agent_framework_devui-1.0.0b251001/samples/foundry_agent/__init__.py +7 -0
- agent_framework_devui-1.0.0b251001/samples/foundry_agent/agent.py +81 -0
- agent_framework_devui-1.0.0b251001/samples/in_memory_mode.py +71 -0
- agent_framework_devui-1.0.0b251001/samples/spam_workflow/__init__.py +7 -0
- agent_framework_devui-1.0.0b251001/samples/spam_workflow/workflow.py +333 -0
- agent_framework_devui-1.0.0b251001/samples/weather_agent/__init__.py +7 -0
- agent_framework_devui-1.0.0b251001/samples/weather_agent/agent.py +69 -0
- agent_framework_devui-1.0.0b251001/samples/weather_agent_azure/__init__.py +7 -0
- agent_framework_devui-1.0.0b251001/samples/weather_agent_azure/agent.py +71 -0
- agent_framework_devui-1.0.0b251001/tests/capture_messages.py +284 -0
- agent_framework_devui-1.0.0b251001/tests/test_discovery.py +99 -0
- agent_framework_devui-1.0.0b251001/tests/test_execution.py +184 -0
- agent_framework_devui-1.0.0b251001/tests/test_mapper.py +419 -0
- agent_framework_devui-1.0.0b251001/tests/test_server.py +132 -0
- agent_framework_devui-0.0.1a0/LICENSE +0 -9
- agent_framework_devui-0.0.1a0/PKG-INFO +0 -18
- agent_framework_devui-0.0.1a0/README.md +0 -3
- agent_framework_devui-0.0.1a0/agent_framework_devui.egg-info/PKG-INFO +0 -18
- agent_framework_devui-0.0.1a0/agent_framework_devui.egg-info/SOURCES.txt +0 -7
- agent_framework_devui-0.0.1a0/agent_framework_devui.egg-info/dependency_links.txt +0 -1
- agent_framework_devui-0.0.1a0/agent_framework_devui.egg-info/top_level.txt +0 -1
- agent_framework_devui-0.0.1a0/pyproject.toml +0 -20
- agent_framework_devui-0.0.1a0/setup.cfg +0 -4
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Microsoft Corporation.
|
|
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
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-framework-devui
|
|
3
|
+
Version: 1.0.0b251001
|
|
4
|
+
Summary: Debug UI for Microsoft Agent Framework with OpenAI-compatible API server.
|
|
5
|
+
Author-email: Microsoft <af-support@microsoft.com>
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: agent-framework-core
|
|
19
|
+
Requires-Dist: fastapi>=0.104.0
|
|
20
|
+
Requires-Dist: uvicorn[standard]>=0.24.0
|
|
21
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
22
|
+
Requires-Dist: pytest>=7.0.0 ; extra == "all"
|
|
23
|
+
Requires-Dist: watchdog>=3.0.0 ; extra == "all"
|
|
24
|
+
Requires-Dist: pytest>=7.0.0 ; extra == "dev"
|
|
25
|
+
Requires-Dist: watchdog>=3.0.0 ; extra == "dev"
|
|
26
|
+
Project-URL: homepage, https://aka.ms/agent-framework
|
|
27
|
+
Project-URL: issues, https://github.com/microsoft/agent-framework/issues
|
|
28
|
+
Project-URL: release_notes, https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true
|
|
29
|
+
Project-URL: source, https://github.com/microsoft/agent-framework/tree/main/python
|
|
30
|
+
Provides-Extra: all
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
|
|
33
|
+
# DevUI - A Sample App for Running Agents and Workflows
|
|
34
|
+
|
|
35
|
+
A lightweight, standalone sample app interface for running entities (agents/workflows) in the Microsoft Agent Framework supporting **directory-based discovery**, **in-memory entity registration**, and **sample entity gallery**.
|
|
36
|
+
|
|
37
|
+
> [!IMPORTANT]
|
|
38
|
+
> DevUI is a **sample app** to help you get started with the Agent Framework. It is **not** intended for production use. For production, or for features beyond what is provided in this sample app, it is recommended that you build your own custom interface and API server using the Agent Framework SDK.
|
|
39
|
+
|
|
40
|
+

|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Install
|
|
46
|
+
pip install agent-framework-devui
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
You can also launch it programmatically
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from agent_framework import ChatAgent
|
|
53
|
+
from agent_framework.openai import OpenAIChatClient
|
|
54
|
+
from agent_framework.devui import serve
|
|
55
|
+
|
|
56
|
+
def get_weather(location: str) -> str:
|
|
57
|
+
"""Get weather for a location."""
|
|
58
|
+
return f"Weather in {location}: 72°F and sunny"
|
|
59
|
+
|
|
60
|
+
# Create your agent
|
|
61
|
+
agent = ChatAgent(
|
|
62
|
+
name="WeatherAgent",
|
|
63
|
+
chat_client=OpenAIChatClient(),
|
|
64
|
+
tools=[get_weather]
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Launch debug UI - that's it!
|
|
68
|
+
serve(entities=[agent], auto_open=True)
|
|
69
|
+
# → Opens browser to http://localhost:8080
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
In addition, if you have agents/workflows defined in a specific directory structure (see below), you can launch DevUI from the _cli_ to discover and run them.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
|
|
76
|
+
# Launch web UI + API server
|
|
77
|
+
devui ./agents --port 8080
|
|
78
|
+
# → Web UI: http://localhost:8080
|
|
79
|
+
# → API: http://localhost:8080/v1/*
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
When DevUI starts with no discovered entities, it displays a **sample entity gallery** with curated examples from the Agent Framework repository to help you get started quickly.
|
|
83
|
+
|
|
84
|
+
## Directory Structure
|
|
85
|
+
|
|
86
|
+
For your agents to be discovered by the DevUI, they must be organized in a directory structure like below. Each agent/workflow must have an `__init__.py` that exports the required variable (`agent` or `workflow`).
|
|
87
|
+
|
|
88
|
+
**Note**: `.env` files are optional but will be automatically loaded if present in the agent/workflow directory or parent entities directory. Use them to store API keys, configuration variables, and other environment-specific settings.
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
agents/
|
|
92
|
+
├── weather_agent/
|
|
93
|
+
│ ├── __init__.py # Must export: agent = ChatAgent(...)
|
|
94
|
+
│ ├── agent.py
|
|
95
|
+
│ └── .env # Optional: API keys, config vars
|
|
96
|
+
├── my_workflow/
|
|
97
|
+
│ ├── __init__.py # Must export: workflow = WorkflowBuilder()...
|
|
98
|
+
│ ├── workflow.py
|
|
99
|
+
│ └── .env # Optional: environment variables
|
|
100
|
+
└── .env # Optional: shared environment variables
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Viewing Telemetry (Otel Traces) in DevUI
|
|
104
|
+
|
|
105
|
+
Agent Framework emits OpenTelemetry (Otel) traces for various operations. You can view these traces in DevUI by enabling tracing when starting the server.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
devui ./agents --tracing framework
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## OpenAI-Compatible API
|
|
112
|
+
|
|
113
|
+
For convenience, you can interact with the agents/workflows using the standard OpenAI API format. Just specify the `entity_id` in the `extra_body` field. This can be an `agent_id` or `workflow_id`.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Standard OpenAI format
|
|
117
|
+
curl -X POST http://localhost:8080/v1/responses \
|
|
118
|
+
-H "Content-Type: application/json" \
|
|
119
|
+
-d @- << 'EOF'
|
|
120
|
+
{
|
|
121
|
+
"model": "agent-framework",
|
|
122
|
+
"input": "Hello world",
|
|
123
|
+
"extra_body": {"entity_id": "weather_agent"}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## CLI Options
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
devui [directory] [options]
|
|
132
|
+
|
|
133
|
+
Options:
|
|
134
|
+
--port, -p Port (default: 8080)
|
|
135
|
+
--host Host (default: 127.0.0.1)
|
|
136
|
+
--headless API only, no UI
|
|
137
|
+
--config YAML config file
|
|
138
|
+
--tracing none|framework|workflow|all
|
|
139
|
+
--reload Enable auto-reload
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Key Endpoints
|
|
143
|
+
|
|
144
|
+
- `GET /v1/entities` - List discovered agents/workflows
|
|
145
|
+
- `GET /v1/entities/{entity_id}/info` - Get detailed entity information
|
|
146
|
+
- `POST /v1/entities/add` - Add entity from URL (for gallery samples)
|
|
147
|
+
- `DELETE /v1/entities/{entity_id}` - Remove remote entity
|
|
148
|
+
- `POST /v1/responses` - Execute agent/workflow (streaming or sync)
|
|
149
|
+
- `GET /health` - Health check
|
|
150
|
+
- `POST /v1/threads` - Create thread for agent (optional)
|
|
151
|
+
- `GET /v1/threads?agent_id={id}` - List threads for agent
|
|
152
|
+
- `GET /v1/threads/{thread_id}` - Get thread info
|
|
153
|
+
- `DELETE /v1/threads/{thread_id}` - Delete thread
|
|
154
|
+
- `GET /v1/threads/{thread_id}/messages` - Get thread messages
|
|
155
|
+
|
|
156
|
+
## Implementation
|
|
157
|
+
|
|
158
|
+
- **Discovery**: `agent_framework_devui/_discovery.py`
|
|
159
|
+
- **Execution**: `agent_framework_devui/_executor.py`
|
|
160
|
+
- **Message Mapping**: `agent_framework_devui/_mapper.py`
|
|
161
|
+
- **Session Management**: `agent_framework_devui/_session.py`
|
|
162
|
+
- **API Server**: `agent_framework_devui/_server.py`
|
|
163
|
+
- **CLI**: `agent_framework_devui/_cli.py`
|
|
164
|
+
|
|
165
|
+
## Examples
|
|
166
|
+
|
|
167
|
+
See `samples/` for working agent and workflow implementations.
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT
|
|
172
|
+
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# DevUI - A Sample App for Running Agents and Workflows
|
|
2
|
+
|
|
3
|
+
A lightweight, standalone sample app interface for running entities (agents/workflows) in the Microsoft Agent Framework supporting **directory-based discovery**, **in-memory entity registration**, and **sample entity gallery**.
|
|
4
|
+
|
|
5
|
+
> [!IMPORTANT]
|
|
6
|
+
> DevUI is a **sample app** to help you get started with the Agent Framework. It is **not** intended for production use. For production, or for features beyond what is provided in this sample app, it is recommended that you build your own custom interface and API server using the Agent Framework SDK.
|
|
7
|
+
|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
## Quick Start
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Install
|
|
14
|
+
pip install agent-framework-devui
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
You can also launch it programmatically
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from agent_framework import ChatAgent
|
|
21
|
+
from agent_framework.openai import OpenAIChatClient
|
|
22
|
+
from agent_framework.devui import serve
|
|
23
|
+
|
|
24
|
+
def get_weather(location: str) -> str:
|
|
25
|
+
"""Get weather for a location."""
|
|
26
|
+
return f"Weather in {location}: 72°F and sunny"
|
|
27
|
+
|
|
28
|
+
# Create your agent
|
|
29
|
+
agent = ChatAgent(
|
|
30
|
+
name="WeatherAgent",
|
|
31
|
+
chat_client=OpenAIChatClient(),
|
|
32
|
+
tools=[get_weather]
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# Launch debug UI - that's it!
|
|
36
|
+
serve(entities=[agent], auto_open=True)
|
|
37
|
+
# → Opens browser to http://localhost:8080
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
In addition, if you have agents/workflows defined in a specific directory structure (see below), you can launch DevUI from the _cli_ to discover and run them.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
|
|
44
|
+
# Launch web UI + API server
|
|
45
|
+
devui ./agents --port 8080
|
|
46
|
+
# → Web UI: http://localhost:8080
|
|
47
|
+
# → API: http://localhost:8080/v1/*
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
When DevUI starts with no discovered entities, it displays a **sample entity gallery** with curated examples from the Agent Framework repository to help you get started quickly.
|
|
51
|
+
|
|
52
|
+
## Directory Structure
|
|
53
|
+
|
|
54
|
+
For your agents to be discovered by the DevUI, they must be organized in a directory structure like below. Each agent/workflow must have an `__init__.py` that exports the required variable (`agent` or `workflow`).
|
|
55
|
+
|
|
56
|
+
**Note**: `.env` files are optional but will be automatically loaded if present in the agent/workflow directory or parent entities directory. Use them to store API keys, configuration variables, and other environment-specific settings.
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
agents/
|
|
60
|
+
├── weather_agent/
|
|
61
|
+
│ ├── __init__.py # Must export: agent = ChatAgent(...)
|
|
62
|
+
│ ├── agent.py
|
|
63
|
+
│ └── .env # Optional: API keys, config vars
|
|
64
|
+
├── my_workflow/
|
|
65
|
+
│ ├── __init__.py # Must export: workflow = WorkflowBuilder()...
|
|
66
|
+
│ ├── workflow.py
|
|
67
|
+
│ └── .env # Optional: environment variables
|
|
68
|
+
└── .env # Optional: shared environment variables
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Viewing Telemetry (Otel Traces) in DevUI
|
|
72
|
+
|
|
73
|
+
Agent Framework emits OpenTelemetry (Otel) traces for various operations. You can view these traces in DevUI by enabling tracing when starting the server.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
devui ./agents --tracing framework
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## OpenAI-Compatible API
|
|
80
|
+
|
|
81
|
+
For convenience, you can interact with the agents/workflows using the standard OpenAI API format. Just specify the `entity_id` in the `extra_body` field. This can be an `agent_id` or `workflow_id`.
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Standard OpenAI format
|
|
85
|
+
curl -X POST http://localhost:8080/v1/responses \
|
|
86
|
+
-H "Content-Type: application/json" \
|
|
87
|
+
-d @- << 'EOF'
|
|
88
|
+
{
|
|
89
|
+
"model": "agent-framework",
|
|
90
|
+
"input": "Hello world",
|
|
91
|
+
"extra_body": {"entity_id": "weather_agent"}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## CLI Options
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
devui [directory] [options]
|
|
100
|
+
|
|
101
|
+
Options:
|
|
102
|
+
--port, -p Port (default: 8080)
|
|
103
|
+
--host Host (default: 127.0.0.1)
|
|
104
|
+
--headless API only, no UI
|
|
105
|
+
--config YAML config file
|
|
106
|
+
--tracing none|framework|workflow|all
|
|
107
|
+
--reload Enable auto-reload
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Key Endpoints
|
|
111
|
+
|
|
112
|
+
- `GET /v1/entities` - List discovered agents/workflows
|
|
113
|
+
- `GET /v1/entities/{entity_id}/info` - Get detailed entity information
|
|
114
|
+
- `POST /v1/entities/add` - Add entity from URL (for gallery samples)
|
|
115
|
+
- `DELETE /v1/entities/{entity_id}` - Remove remote entity
|
|
116
|
+
- `POST /v1/responses` - Execute agent/workflow (streaming or sync)
|
|
117
|
+
- `GET /health` - Health check
|
|
118
|
+
- `POST /v1/threads` - Create thread for agent (optional)
|
|
119
|
+
- `GET /v1/threads?agent_id={id}` - List threads for agent
|
|
120
|
+
- `GET /v1/threads/{thread_id}` - Get thread info
|
|
121
|
+
- `DELETE /v1/threads/{thread_id}` - Delete thread
|
|
122
|
+
- `GET /v1/threads/{thread_id}/messages` - Get thread messages
|
|
123
|
+
|
|
124
|
+
## Implementation
|
|
125
|
+
|
|
126
|
+
- **Discovery**: `agent_framework_devui/_discovery.py`
|
|
127
|
+
- **Execution**: `agent_framework_devui/_executor.py`
|
|
128
|
+
- **Message Mapping**: `agent_framework_devui/_mapper.py`
|
|
129
|
+
- **Session Management**: `agent_framework_devui/_session.py`
|
|
130
|
+
- **API Server**: `agent_framework_devui/_server.py`
|
|
131
|
+
- **CLI**: `agent_framework_devui/_cli.py`
|
|
132
|
+
|
|
133
|
+
## Examples
|
|
134
|
+
|
|
135
|
+
See `samples/` for working agent and workflow implementations.
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Copyright (c) Microsoft. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Agent Framework DevUI - Debug interface with OpenAI compatible API server."""
|
|
4
|
+
|
|
5
|
+
import importlib.metadata
|
|
6
|
+
import logging
|
|
7
|
+
import webbrowser
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from ._server import DevServer
|
|
11
|
+
from .models import AgentFrameworkRequest, OpenAIError, OpenAIResponse, ResponseStreamEvent
|
|
12
|
+
from .models._discovery_models import DiscoveryResponse, EntityInfo, EnvVarRequirement
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
__version__ = importlib.metadata.version(__name__)
|
|
18
|
+
except importlib.metadata.PackageNotFoundError:
|
|
19
|
+
__version__ = "0.0.0" # Fallback for development mode
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def serve(
|
|
23
|
+
entities: list[Any] | None = None,
|
|
24
|
+
entities_dir: str | None = None,
|
|
25
|
+
port: int = 8080,
|
|
26
|
+
host: str = "127.0.0.1",
|
|
27
|
+
auto_open: bool = False,
|
|
28
|
+
cors_origins: list[str] | None = None,
|
|
29
|
+
ui_enabled: bool = True,
|
|
30
|
+
tracing_enabled: bool = False,
|
|
31
|
+
) -> None:
|
|
32
|
+
"""Launch Agent Framework DevUI with simple API.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
entities: List of entities for in-memory registration (IDs auto-generated)
|
|
36
|
+
entities_dir: Directory to scan for entities
|
|
37
|
+
port: Port to run server on
|
|
38
|
+
host: Host to bind server to
|
|
39
|
+
auto_open: Whether to automatically open browser
|
|
40
|
+
cors_origins: List of allowed CORS origins
|
|
41
|
+
ui_enabled: Whether to enable the UI
|
|
42
|
+
tracing_enabled: Whether to enable OpenTelemetry tracing
|
|
43
|
+
"""
|
|
44
|
+
import re
|
|
45
|
+
|
|
46
|
+
import uvicorn
|
|
47
|
+
|
|
48
|
+
# Validate host parameter early for security
|
|
49
|
+
if not re.match(r"^(localhost|127\.0\.0\.1|0\.0\.0\.0|[a-zA-Z0-9.-]+)$", host):
|
|
50
|
+
raise ValueError(f"Invalid host: {host}. Must be localhost, IP address, or valid hostname")
|
|
51
|
+
|
|
52
|
+
# Validate port parameter
|
|
53
|
+
if not isinstance(port, int) or not (1 <= port <= 65535):
|
|
54
|
+
raise ValueError(f"Invalid port: {port}. Must be integer between 1 and 65535")
|
|
55
|
+
|
|
56
|
+
# Configure tracing environment variables if enabled
|
|
57
|
+
if tracing_enabled:
|
|
58
|
+
import os
|
|
59
|
+
|
|
60
|
+
# Only set if not already configured by user
|
|
61
|
+
if not os.environ.get("ENABLE_OTEL"):
|
|
62
|
+
os.environ["ENABLE_OTEL"] = "true"
|
|
63
|
+
logger.info("Set ENABLE_OTEL=true for tracing")
|
|
64
|
+
|
|
65
|
+
if not os.environ.get("ENABLE_SENSITIVE_DATA"):
|
|
66
|
+
os.environ["ENABLE_SENSITIVE_DATA"] = "true"
|
|
67
|
+
logger.info("Set ENABLE_SENSITIVE_DATA=true for tracing")
|
|
68
|
+
|
|
69
|
+
if not os.environ.get("OTLP_ENDPOINT"):
|
|
70
|
+
os.environ["OTLP_ENDPOINT"] = "http://localhost:4317"
|
|
71
|
+
logger.info("Set OTLP_ENDPOINT=http://localhost:4317 for tracing")
|
|
72
|
+
|
|
73
|
+
# Create server with direct parameters
|
|
74
|
+
server = DevServer(
|
|
75
|
+
entities_dir=entities_dir, port=port, host=host, cors_origins=cors_origins, ui_enabled=ui_enabled
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Register in-memory entities if provided
|
|
79
|
+
if entities:
|
|
80
|
+
logger.info(f"Registering {len(entities)} in-memory entities")
|
|
81
|
+
# Store entities for later registration during server startup
|
|
82
|
+
server._pending_entities = entities
|
|
83
|
+
|
|
84
|
+
app = server.get_app()
|
|
85
|
+
|
|
86
|
+
if auto_open:
|
|
87
|
+
|
|
88
|
+
def open_browser() -> None:
|
|
89
|
+
import http.client
|
|
90
|
+
import re
|
|
91
|
+
import time
|
|
92
|
+
|
|
93
|
+
# Validate host and port for security
|
|
94
|
+
if not re.match(r"^(localhost|127\.0\.0\.1|0\.0\.0\.0|[a-zA-Z0-9.-]+)$", host):
|
|
95
|
+
logger.warning(f"Invalid host for auto-open: {host}")
|
|
96
|
+
return
|
|
97
|
+
|
|
98
|
+
if not isinstance(port, int) or not (1 <= port <= 65535):
|
|
99
|
+
logger.warning(f"Invalid port for auto-open: {port}")
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
# Wait for server to be ready by checking health endpoint
|
|
103
|
+
browser_url = f"http://{host}:{port}"
|
|
104
|
+
|
|
105
|
+
for _ in range(30): # 15 second timeout (30 * 0.5s)
|
|
106
|
+
try:
|
|
107
|
+
# Use http.client for safe connection handling (standard library)
|
|
108
|
+
conn = http.client.HTTPConnection(host, port, timeout=1)
|
|
109
|
+
try:
|
|
110
|
+
conn.request("GET", "/health")
|
|
111
|
+
response = conn.getresponse()
|
|
112
|
+
if response.status == 200:
|
|
113
|
+
webbrowser.open(browser_url)
|
|
114
|
+
return
|
|
115
|
+
finally:
|
|
116
|
+
conn.close()
|
|
117
|
+
except (http.client.HTTPException, OSError, TimeoutError):
|
|
118
|
+
pass
|
|
119
|
+
time.sleep(0.5)
|
|
120
|
+
|
|
121
|
+
# Fallback: open browser anyway after timeout
|
|
122
|
+
webbrowser.open(browser_url)
|
|
123
|
+
|
|
124
|
+
import threading
|
|
125
|
+
|
|
126
|
+
threading.Thread(target=open_browser, daemon=True).start()
|
|
127
|
+
|
|
128
|
+
logger.info(f"Starting Agent Framework DevUI on {host}:{port}")
|
|
129
|
+
uvicorn.run(app, host=host, port=port, log_level="info")
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def main() -> None:
|
|
133
|
+
"""CLI entry point for devui command."""
|
|
134
|
+
from ._cli import main as cli_main
|
|
135
|
+
|
|
136
|
+
cli_main()
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# Export main public API
|
|
140
|
+
__all__ = [
|
|
141
|
+
"AgentFrameworkRequest",
|
|
142
|
+
"DevServer",
|
|
143
|
+
"DiscoveryResponse",
|
|
144
|
+
"EntityInfo",
|
|
145
|
+
"EnvVarRequirement",
|
|
146
|
+
"OpenAIError",
|
|
147
|
+
"OpenAIResponse",
|
|
148
|
+
"ResponseStreamEvent",
|
|
149
|
+
"main",
|
|
150
|
+
"serve",
|
|
151
|
+
]
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Copyright (c) Microsoft. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Command line interface for Agent Framework DevUI."""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def setup_logging(level: str = "INFO") -> None:
|
|
14
|
+
"""Configure logging for the server."""
|
|
15
|
+
log_format = "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
|
|
16
|
+
logging.basicConfig(level=getattr(logging, level.upper()), format=log_format, datefmt="%Y-%m-%d %H:%M:%S")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def create_cli_parser() -> argparse.ArgumentParser:
|
|
20
|
+
"""Create the command line argument parser."""
|
|
21
|
+
parser = argparse.ArgumentParser(
|
|
22
|
+
prog="devui",
|
|
23
|
+
description="Launch Agent Framework DevUI - Debug interface with OpenAI compatible API",
|
|
24
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
25
|
+
epilog="""
|
|
26
|
+
Examples:
|
|
27
|
+
devui # Scan current directory
|
|
28
|
+
devui ./agents # Scan specific directory
|
|
29
|
+
devui --port 8000 # Custom port
|
|
30
|
+
devui --headless # API only, no UI
|
|
31
|
+
devui --tracing # Enable OpenTelemetry tracing
|
|
32
|
+
""",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
parser.add_argument(
|
|
36
|
+
"directory", nargs="?", default=".", help="Directory to scan for entities (default: current directory)"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
parser.add_argument("--port", "-p", type=int, default=8080, help="Port to run server on (default: 8080)")
|
|
40
|
+
|
|
41
|
+
parser.add_argument("--host", default="127.0.0.1", help="Host to bind server to (default: 127.0.0.1)")
|
|
42
|
+
|
|
43
|
+
parser.add_argument("--no-open", action="store_true", help="Don't automatically open browser")
|
|
44
|
+
|
|
45
|
+
parser.add_argument("--headless", action="store_true", help="Run without UI (API only)")
|
|
46
|
+
|
|
47
|
+
parser.add_argument(
|
|
48
|
+
"--log-level",
|
|
49
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
|
|
50
|
+
default="INFO",
|
|
51
|
+
help="Logging level (default: INFO)",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
parser.add_argument("--reload", action="store_true", help="Enable auto-reload for development")
|
|
55
|
+
|
|
56
|
+
parser.add_argument("--tracing", action="store_true", help="Enable OpenTelemetry tracing for Agent Framework")
|
|
57
|
+
|
|
58
|
+
parser.add_argument("--version", action="version", version=f"Agent Framework DevUI {get_version()}")
|
|
59
|
+
|
|
60
|
+
return parser
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_version() -> str:
|
|
64
|
+
"""Get the package version."""
|
|
65
|
+
try:
|
|
66
|
+
from . import __version__
|
|
67
|
+
|
|
68
|
+
return __version__
|
|
69
|
+
except ImportError:
|
|
70
|
+
return "unknown"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def validate_directory(directory: str) -> str:
|
|
74
|
+
"""Validate and normalize the entities directory."""
|
|
75
|
+
if not directory:
|
|
76
|
+
directory = "."
|
|
77
|
+
|
|
78
|
+
abs_dir = os.path.abspath(directory)
|
|
79
|
+
|
|
80
|
+
if not os.path.exists(abs_dir):
|
|
81
|
+
print(f"❌ Error: Directory '{directory}' does not exist", file=sys.stderr) # noqa: T201
|
|
82
|
+
sys.exit(1)
|
|
83
|
+
|
|
84
|
+
if not os.path.isdir(abs_dir):
|
|
85
|
+
print(f"❌ Error: '{directory}' is not a directory", file=sys.stderr) # noqa: T201
|
|
86
|
+
sys.exit(1)
|
|
87
|
+
|
|
88
|
+
return abs_dir
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def print_startup_info(entities_dir: str, host: str, port: int, ui_enabled: bool, reload: bool) -> None:
|
|
92
|
+
"""Print startup information."""
|
|
93
|
+
print("🤖 Agent Framework DevUI") # noqa: T201
|
|
94
|
+
print("=" * 50) # noqa: T201
|
|
95
|
+
print(f"📁 Entities directory: {entities_dir}") # noqa: T201
|
|
96
|
+
print(f"🌐 Server URL: http://{host}:{port}") # noqa: T201
|
|
97
|
+
print(f"🎨 UI enabled: {'Yes' if ui_enabled else 'No'}") # noqa: T201
|
|
98
|
+
print(f"🔄 Auto-reload: {'Yes' if reload else 'No'}") # noqa: T201
|
|
99
|
+
print("=" * 50) # noqa: T201
|
|
100
|
+
print("🔍 Scanning for entities...") # noqa: T201
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def main() -> None:
|
|
104
|
+
"""Main CLI entry point."""
|
|
105
|
+
parser = create_cli_parser()
|
|
106
|
+
args = parser.parse_args()
|
|
107
|
+
|
|
108
|
+
# Setup logging
|
|
109
|
+
setup_logging(args.log_level)
|
|
110
|
+
|
|
111
|
+
# Validate directory
|
|
112
|
+
entities_dir = validate_directory(args.directory)
|
|
113
|
+
|
|
114
|
+
# Extract parameters directly from args
|
|
115
|
+
ui_enabled = not args.headless
|
|
116
|
+
|
|
117
|
+
# Print startup info
|
|
118
|
+
print_startup_info(entities_dir, args.host, args.port, ui_enabled, args.reload)
|
|
119
|
+
|
|
120
|
+
# Import and start server
|
|
121
|
+
try:
|
|
122
|
+
from . import serve
|
|
123
|
+
|
|
124
|
+
serve(
|
|
125
|
+
entities_dir=entities_dir,
|
|
126
|
+
port=args.port,
|
|
127
|
+
host=args.host,
|
|
128
|
+
auto_open=not args.no_open,
|
|
129
|
+
ui_enabled=ui_enabled,
|
|
130
|
+
tracing_enabled=args.tracing,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
except KeyboardInterrupt:
|
|
134
|
+
print("\n👋 Shutting down Agent Framework DevUI...") # noqa: T201
|
|
135
|
+
sys.exit(0)
|
|
136
|
+
except Exception as e:
|
|
137
|
+
logger.exception("Failed to start server")
|
|
138
|
+
print(f"❌ Error: {e}", file=sys.stderr) # noqa: T201
|
|
139
|
+
sys.exit(1)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
if __name__ == "__main__":
|
|
143
|
+
main()
|