Skip to content

Commit bd0309e

Browse files
Merge remote-tracking branch 'origin/main' into fix/truncation_strategy
2 parents 237c3fe + 3c74720 commit bd0309e

20 files changed

Lines changed: 1263 additions & 436 deletions

README.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,37 @@ Ready to build your first agent? Check out our documentation:
129129

130130
## Quick Install
131131

132+
```bash
133+
pip install askui
134+
```
135+
136+
**Requires Python >=3.10*
137+
138+
The default install includes core dependencies (Agent OS client, HTTP, common model APIs, Android tooling, etc.). Add **optional extras** only when you need the features below.
139+
132140
```bash
133141
pip install askui[all]
134142
```
135143

136-
**Requires Python >=3.10, <3.14**
144+
`all` pulls in every optional extra in one command (larger install). Prefer picking individual extras when you know what you need. Or start using AskUI with a minimal install and add extras as you need them.
145+
146+
### Optional install extras
147+
148+
| Extra | When to use it |
149+
| --- | --- |
150+
| *(none)* | Everyday automation. Smallest footprint. |
151+
| `all` | You want every optional integration below without choosing extras (CI images, demos, or “install everything once”). |
152+
| `office-document` | Reading or converting **Office files** (Excel `.xls`/`.xlsx`, Word `.docx`) via MarkItDown—e.g. extracting content from spreadsheets or documents in workflows. To be used in `get()` methods. |
153+
| `bedrock` | Running **Anthropic Claude through AWS Bedrock** (`anthropic[bedrock]`). Use when your org routes Claude via Bedrock, not the direct Anthropic API. |
154+
| `vertex` | Running **Anthropic Claude on Google Vertex AI** plus Vertex client libraries. Use when models are hosted on Vertex, not only the public Anthropic API. |
155+
| `otel` | **OpenTelemetry** export and instrumentation you enable in code: OTLP over HTTP, plus optional instrumentation for `httpx` and SQLAlchemy. Use for production tracing/metrics pipelines—not required for local scripts. |
156+
| `web` | **Browser automation with Playwright** (e.g. web-focused agents and Playwright-backed flows). Core desktop control still uses Agent OS; this extra is for the Playwright stack. |
157+
158+
Combine extras as needed, for example:
159+
160+
```bash
161+
pip install askui[bedrock,otel]
162+
```
137163

138164
You'll also need to install AskUI Agent OS for device control. See [Setup Guide](docs/01_setup.md) for detailed instructions.
139165

docs/01_setup.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This guide will get AskUI Vision Agent installed and configured on your system.
44

55
## Python Package Installation
66

7-
AskUI Vision Agent requires Python >=3.10, and <3.14.
7+
AskUI Vision Agent requires Python >=3.10 and <3.14.
88

99
For installing the python-sdk please run
1010

docs/09_observability_telemetry_tracing.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ Set the following environment variables to configure tracing. All variables use
9292
| `ASKUI__OTEL_ENDPOINT` | OTLP HTTP endpoint URL ||
9393
| `ASKUI__OTEL_SERVICE_NAME` | Service name reported in traces | `askui-python-sdk` |
9494
| `ASKUI__OTEL_SERVICE_VERSION` | Service version reported in traces | Current package version |
95-
| `ASKUI__OTEL_CLUSTER_NAME` | Cluster name reported in traces | `askui-dev` |
9695

9796
#### Linux & MacOS
9897
```bash
@@ -132,7 +131,6 @@ from askui.telemetry.otel import OtelSettings
132131

133132
settings = OtelSettings(
134133
enabled=True,
135-
service_name="my-custom-service",
136-
cluster_name="production",
134+
service_name="my-custom-service"
137135
)
138136
```

docs/10_extracting_data.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ The AskUI Python SDK supports the use of various file formats.
4343
- Word Files (.docx, .doc)
4444
- CSV Files (.csv)
4545

46+
**Office documents (Excel and Word)** are loaded as `OfficeDocumentSource` and converted to Markdown with MarkItDown. That stack is optional: the base `askui` install does not include it. Install AskUI with the **office-document** extra when you use Excel or Word as `get()` sources:
47+
48+
```bash
49+
pip install "askui[office-document]"
50+
```
51+
4652
**Model Compatibility Matrix**
4753

4854
| File Format | AskUI Gemini | Anthropic Claude | Google Gemini

mypy.ini

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ namespace_packages = true
2424
[mypy-jsonref.*]
2525
ignore_missing_imports = true
2626

27-
[mypy-bson.*]
28-
ignore_missing_imports = true
29-
3027
[mypy-alembic.*]
3128
ignore_missing_imports = true
3229

pdm.lock

Lines changed: 824 additions & 324 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,16 @@ dependencies = [
2828
"protobuf>=6.31.1",
2929
"google-genai>=1.20.0",
3030
"filetype>=1.2.0",
31-
"markitdown[xls,xlsx,docx]>=0.1.2",
3231
"asyncer==0.0.8",
33-
"bson>=0.5.10",
3432
"aiofiles>=24.1.0",
3533
"anyio==4.10.0", # We need to pin this version otherwise listing mcp tools using fastmcp within runner fails
3634
"sqlalchemy[mypy]>=2.0.44",
3735
"apscheduler==4.0.0a6",
3836
"opentelemetry-api>=1.38.0",
39-
"imagehash>=4.3.0",
37+
"imagehash>=4.3.0", # requires python <3.14 because of dependency on scipy
38+
"pure-python-adb>=0.3.0.dev0"
4039
]
41-
requires-python = ">=3.10,<3.14"
40+
requires-python = ">=3.10, <3.14"
4241
readme = "README.md"
4342
license = {text = "MIT"}
4443
dynamic = ["version"]
@@ -217,9 +216,9 @@ known-first-party = ["askui"]
217216
known-third-party = ["pytest", "mypy"]
218217

219218
[project.optional-dependencies]
220-
all = ["askui[android,bedrock,otel,vertex,web]"]
221-
android = [
222-
"pure-python-adb>=0.3.0.dev0"
219+
all = ["askui[office-document,bedrock,otel,vertex,web]"]
220+
office-document = [
221+
"markitdown[xls,xlsx,docx]>=0.1.2"
223222
]
224223
bedrock = [
225224
"anthropic[bedrock]>=0.72.0"
@@ -228,7 +227,6 @@ otel = [
228227
"opentelemetry-api>=1.38.0",
229228
"opentelemetry-exporter-otlp-proto-http>=1.38.0",
230229
"opentelemetry-instrumentation-httpx>=0.59b0",
231-
"opentelemetry-instrumentation-sqlalchemy>=0.59b0",
232230
]
233231
vertex = [
234232
"google-cloud-aiplatform>=1.122.0",

src/askui/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""AskUI Python SDK"""
22

3-
__version__ = "0.27.0"
3+
__version__ = "0.28.0"
44

55
import logging
66
import os

src/askui/models/shared/conversation.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -293,12 +293,7 @@ def _execute_step(self) -> bool:
293293
self._switch_speaker_if_needed()
294294

295295
# 2. Get next message(s) from speaker and add to history
296-
logger.debug("Executing step with speaker: %s", self.current_speaker.name)
297-
result: SpeakerResult = self.current_speaker.handle_step(
298-
self, self.cache_manager
299-
)
300-
for message in result.messages_to_add:
301-
self._add_message(message)
296+
result = self._get_next_message()
302297

303298
# 3. Execute tool calls if applicable
304299
continue_loop = False
@@ -320,6 +315,16 @@ def _execute_step(self) -> bool:
320315

321316
return continue_loop
322317

318+
@tracer.start_as_current_span("_get_next_message")
319+
def _get_next_message(self) -> SpeakerResult:
320+
logger.debug("Executing step with speaker: %s", self.current_speaker.name)
321+
result: SpeakerResult = self.current_speaker.handle_step(
322+
self, self.cache_manager
323+
)
324+
for message in result.messages_to_add:
325+
self._add_message(message)
326+
return result
327+
323328
@tracer.start_as_current_span("_execute_tools_if_present")
324329
def _execute_tools_if_present(self, message: MessageParam) -> MessageParam | None:
325330
"""Execute tools if the message contains tool use blocks.

src/askui/reporting.py

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,26 +37,34 @@ def normalize_to_pil_images(
3737
return [image]
3838

3939

40-
def truncate_content(
41-
content: Any,
42-
max_string_length: int = 100000,
43-
) -> Any:
44-
"""Filter out long strings (i.e. the base64 image data) to keep reports readable."""
45-
if isinstance(content, str):
46-
if len(content) > max_string_length:
47-
return f"[truncated: {len(content)} characters]"
48-
return content
49-
40+
def truncate_base64_images(content: Any) -> Any:
41+
"""Replace base64 image data with a placeholder to keep reports readable.
42+
43+
Walks the message content recursively and replaces the ``data`` field of
44+
any base64 image source block (matching the schema of
45+
``Base64ImageSourceParam``, i.e. ``{"type": "base64", "data": "...",
46+
"media_type": "image/..."}``) with a placeholder string. All other
47+
content (including regular long strings like prompts or tool outputs)
48+
is left untouched.
49+
"""
5050
if isinstance(content, dict):
51+
content_dict: dict[Any, Any] = content
52+
media_type = content_dict.get("media_type")
53+
if (
54+
isinstance(media_type, str)
55+
and media_type.startswith("image/")
56+
and content_dict.get("type") == "base64"
57+
and "data" in content_dict
58+
):
59+
return {**content_dict, "data": "[Base64 image data truncated]"}
5160
return {
52-
key: truncate_content(value, max_string_length)
53-
for key, value in content.items()
61+
key: truncate_base64_images(value) for key, value in content_dict.items()
5462
}
5563

5664
if isinstance(content, list):
57-
return [truncate_content(item, max_string_length) for item in content]
65+
content_list: list[Any] = content
66+
return [truncate_base64_images(item) for item in content_list]
5867

59-
# For other types (int, float, bool, None), return as-is
6068
return content
6169

6270

@@ -257,7 +265,7 @@ def add_message(
257265
self._start_time = datetime.now(tz=timezone.utc)
258266

259267
_images = normalize_to_pil_images(image)
260-
_content = truncate_content(content)
268+
_content = truncate_base64_images(content)
261269

262270
message = {
263271
"timestamp": datetime.now(tz=timezone.utc),

0 commit comments

Comments
 (0)