Skip to content

V0.1.x #69

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ hatch fmt --linter

If you're using an IDE like VS Code or PyCharm, consider configuring it to use these tools automatically.

For additional details on styling, please see our dedicated [Style Guide](./STYLE_GUIDE.md).


## Contributing via Pull Requests
Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,11 @@ agent = Agent(model=bedrock_model)
agent("Tell me about Agentic AI")

# Ollama
ollama_modal = OllamaModel(
ollama_model = OllamaModel(
host="http://localhost:11434",
model_id="llama3"
)
agent = Agent(model=ollama_modal)
agent = Agent(model=ollama_model)
agent("Tell me about Agentic AI")

# Llama API
Expand Down
59 changes: 59 additions & 0 deletions STYLE_GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Style Guide

## Overview

The Strands Agents style guide aims to establish consistent formatting, naming conventions, and structure across all code in the repository. We strive to make our code clean, readable, and maintainable.

Where possible, we will codify these style guidelines into our linting rules and pre-commit hooks to automate enforcement and reduce the manual review burden.

## Log Formatting

The format for Strands Agents logs is as follows:

```python
logger.debug("field1=<%s>, field2=<%s>, ... | human readable message", field1, field2, ...)
```

### Guidelines

1. **Context**:
- Add context as `<FIELD>=<VALUE>` pairs at the beginning of the log
- Many log services (CloudWatch, Splunk, etc.) look for these patterns to extract fields for searching
- Use `,`'s to separate pairs
- Enclose values in `<>` for readability
- This is particularly helpful in displaying empty values (`field=` vs `field=<>`)
- Use `%s` for string interpolation as recommended by Python logging
- This is an optimization to skip string interpolation when the log level is not enabled

1. **Messages**:
- Add human readable messages at the end of the log
- Use lowercase for consistency
- Avoid punctuation (periods, exclamation points, etc.) to reduce clutter
- Keep messages concise and focused on a single statement
- If multiple statements are needed, separate them with the pipe character (`|`)
- Example: `"processing request | starting validation"`

### Examples

#### Good

```python
logger.debug("user_id=<%s>, action=<%s> | user performed action", user_id, action)
logger.info("request_id=<%s>, duration_ms=<%d> | request completed", request_id, duration)
logger.warning("attempt=<%d>, max_attempts=<%d> | retry limit approaching", attempt, max_attempts)
```

#### Poor

```python
# Avoid: No structured fields, direct variable interpolation in message
logger.debug(f"User {user_id} performed action {action}")

# Avoid: Inconsistent formatting, punctuation
logger.info("Request completed in %d ms.", duration)

# Avoid: No separation between fields and message
logger.warning("Retry limit approaching! attempt=%d max_attempts=%d", attempt, max_attempts)
```

By following these log formatting guidelines, we ensure that logs are both human-readable and machine-parseable, making debugging and monitoring more efficient.
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "strands-agents"
version = "0.1.2"
version = "0.1.3"
description = "A model-driven approach to building AI agents in just a few lines of code"
readme = "README.md"
requires-python = ">=3.10"
Expand Down Expand Up @@ -185,7 +185,9 @@ select = [
"D", # pydocstyle
"E", # pycodestyle
"F", # pyflakes
"G", # logging format
"I", # isort
"LOG", # logging
]

[tool.ruff.lint.per-file-ignores]
Expand Down
4 changes: 2 additions & 2 deletions src/strands/agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
The Agent interface supports two complementary interaction patterns:

1. Natural language for conversation: `agent("Analyze this data")`
2. Method-style for direct tool access: `agent.tool_name(param1="value")`
2. Method-style for direct tool access: `agent.tool.tool_name(param1="value")`
"""

import asyncio
Expand Down Expand Up @@ -515,7 +515,7 @@ def _record_tool_execution(
"""
# Create user message describing the tool call
user_msg_content = [
{"text": (f"agent.{tool['name']} direct tool call\nInput parameters: {json.dumps(tool['input'])}\n")}
{"text": (f"agent.tool.{tool['name']} direct tool call.\nInput parameters: {json.dumps(tool['input'])}\n")}
]

# Add override message if provided
Expand Down
10 changes: 5 additions & 5 deletions src/strands/telemetry/tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def __init__(
headers_dict[key.strip()] = value.strip()
otlp_headers = headers_dict
except Exception as e:
logger.warning(f"error=<{e}> | failed to parse OTEL_EXPORTER_OTLP_HEADERS")
logger.warning("error=<%s> | failed to parse OTEL_EXPORTER_OTLP_HEADERS", e)

self.service_name = service_name
self.otlp_endpoint = otlp_endpoint
Expand Down Expand Up @@ -184,9 +184,9 @@ def _initialize_tracer(self) -> None:

batch_processor = BatchSpanProcessor(otlp_exporter)
self.tracer_provider.add_span_processor(batch_processor)
logger.info(f"endpoint=<{endpoint}> | OTLP exporter configured with endpoint")
logger.info("endpoint=<%s> | OTLP exporter configured with endpoint", endpoint)
except Exception as e:
logger.error(f"error=<{e}> | Failed to configure OTLP exporter", exc_info=True)
logger.exception("error=<%s> | Failed to configure OTLP exporter", e)

# Set as global tracer provider
trace.set_tracer_provider(self.tracer_provider)
Expand Down Expand Up @@ -267,15 +267,15 @@ def _end_span(
else:
span.set_status(StatusCode.OK)
except Exception as e:
logger.warning(f"error=<{e}> | error while ending span", exc_info=True)
logger.warning("error=<%s> | error while ending span", e, exc_info=True)
finally:
span.end()
# Force flush to ensure spans are exported
if self.tracer_provider:
try:
self.tracer_provider.force_flush()
except Exception as e:
logger.warning(f"error=<{e}> | failed to force flush tracer provider")
logger.warning("error=<%s> | failed to force flush tracer provider", e)

def end_span_with_error(self, span: trace.Span, error_message: str, exception: Optional[Exception] = None) -> None:
"""End a span with error status.
Expand Down
2 changes: 1 addition & 1 deletion tests/strands/agent/test_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ def test_agent_tool_user_message_override(agent):
},
{
"text": (
"agent.tool_decorated direct tool call\n"
"agent.tool.tool_decorated direct tool call.\n"
"Input parameters: "
'{"random_string": "abcdEfghI123", "user_message_override": "test override"}\n'
),
Expand Down
Loading