-
Notifications
You must be signed in to change notification settings - Fork 3
Docker build #9
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
base: main
Are you sure you want to change the base?
Docker build #9
Conversation
The workflow file 'claude.yml' has been moved from the 'workflows' directory to the '.github/workflows' directory to adhere to GitHub's standard directory structure for workflows.
Implements comprehensive YAML format support as an alternative to the existing Dockerfile-like format: - Add AgentfileYamlParser with complete YAML schema support - Add JSON schema validation for YAML format - Add format auto-detection based on file extension and content - Add CLI flags: --format, --from-yaml for explicit format control - Add conversion utilities (agentman convert, agentman validate) - Add comprehensive test suite for YAML parser - Add example YAML Agentfile configurations - Maintain 100% backwards compatibility with existing Dockerfile format New CLI commands: - agentman convert: Convert between Dockerfile and YAML formats - agentman validate: Validate Agentfile in either format All existing functionality preserved while adding powerful new YAML support for more familiar and structured configuration management. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Owen Zanzal <AgentO3@users.noreply.github.com>
- Run tests on Python 3.10, 3.11, 3.12, 3.13 - Use uv for dependency management - Include coverage reporting with codecov - Add code quality checks (black, isort, pylint) - Trigger on push to main and pull requests Co-authored-by: Owen Zanzal <AgentO3@users.noreply.github.com>
- Fixed test_build_from_agentfile and test_build_from_agentfile_default_output to mock agentman.yaml_parser.parse_agentfile instead of AgentfileParser - Fixed import ordering with isort and formatting with black - All 95 tests now pass 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Owen Zanzal <AgentO3@users.noreply.github.com>
- Fix import-outside-toplevel errors by moving imports to module level - Remove unnecessary else/elif statements after return statements - Fix unused imports and variables - Remove unnecessary pass statements in abstract methods - Fix broad exception catching with specific exceptions - Fix trailing whitespace issues - Improve code quality from 9.78/10 to 9.99/10 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Owen Zanzal <AgentO3@users.noreply.github.com>
- Fix mock paths in test_agent_builder.py for parse_agentfile function - Add too-many-locals to pylint disabled warnings in pyproject.toml - All 95 tests now pass - Pylint score improved to 10.00/10 Co-authored-by: Owen Zanzal <AgentO3@users.noreply.github.com>
- Updated the Agentfile schema to support multiple agents by changing the `agent` field to `agents`, which is now an array. - Modified the YAML parser to handle multiple agents and convert single agent configurations to the new format. - Updated the converter to handle multiple agents and convert them to YAML format correctly. - Added tests to ensure multiple agents are parsed and converted correctly. - Removed the `yaml-example` as it is no longer compatible with the new schema.
- Updated `AgentfileYamlParser` to parse routers, chains, and orchestrators. - Enhanced `converter.py` to handle routers, chains, and orchestrators in YAML and Dockerfile conversion. - Modified `.gitignore` to include `build/` directory. - Updated `Agentfile.yml` to include a new orchestrator configuration.
- Introduced YAML format for defining agent configurations, providing better structure for complex workflows. - Updated README with examples and instructions for both Dockerfile and YAML formats. - Enhanced file format support section to highlight advantages of YAML, including IDE support and clear hierarchy. - Updated example projects to include both Dockerfile-style and YAML format Agentfiles for comparison and learning. - Added YAML format examples for MCP servers, agent definitions, workflow orchestration, and secrets management.
This commit addresses several formatting issues in the agentman module, specifically in the agentfile_schema.py, cli.py, and yaml_parser.py files. The changes include: - Corrected the indentation and structure of the "default" property in the AGENTFILE_YAML_SCHEMA dictionary in agentfile_schema.py for better readability. - Removed unnecessary string concatenations in help messages in cli.py to improve clarity. - Removed trailing whitespace in yaml_parser.py to adhere to coding standards.
feat: Add YAML format support for Agentfile configurations
…tion
This implements a better way to pass MCP secrets through environment variables
instead of hardcoding them in the Agentfile. Now users can use ${ENV_VAR} or
$ENV_VAR syntax in:
- SECRET values: SECRET API_KEY ${API_KEY}
- MCP server ENV: ENV GITHUB_TOKEN ${GITHUB_TOKEN}
Key features:
- Supports both ${VAR} and $VAR syntax
- Works in both Agentfile and YAML formats
- Maintains backward compatibility with hardcoded values
- Gracefully handles missing environment variables
Resolves: #4
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-authored-by: Owen Zanzal <AgentO3@users.noreply.github.com>
…unnecessary else clause
Add environment variable support for MCP secrets
- Add output_format field to Agent schema supporting inline YAML JSONSchema and external file references - Support both .json and .yaml/.yml external schema files - Update Dockerfile-style parser to handle OUTPUT_FORMAT instruction - Update YAML parser to handle output_format field - Add comprehensive examples in structured-output-example/ - Maintain backward compatibility with existing Agentfile configurations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Owen Zanzal <AgentO3@users.noreply.github.com>
- Updated Agentfile.yml to use the gpt-4.1 model instead of anthropic/claude-3-sonnet. - Enhanced `agentfile_parser.py` to support output formats with JSON schema and external schema files. - Added methods to generate request parameters from JSON schema and external files. - Improved path handling for schema files by resolving relative paths based on the Agentfile location. - Updated `fast_agent.py` to import `RequestParams` and pass the base path for decorator string generation.
- Removed unnecessary line breaks and simplified the construction of the `response_format` dictionary in `agentfile_parser.py`. - Removed trailing whitespace and added missing line breaks for better code readability. - Updated `AGENTFILE_YAML_SCHEMA` in `agentfile_schema.py` to improve consistency in formatting and added missing commas. - Ensured consistent error handling and validation in `yaml_parser.py` by removing unnecessary whitespace. - Modified GitHub Actions workflow to run `black` without the `--check` flag, allowing automatic code formatting.
- Introduced structured output format using JSONSchema for agent outputs. - Added support for inline JSONSchema definitions in both Dockerfile and YAML formats. - Enabled referencing external schema files for output validation. - Enhanced type safety and documentation through schema validation. - Updated `agentfile_parser.py` to handle JSONSchema and schema file references. - Improved error handling for invalid schema definitions.
- Added YAML parsing capability to handle inline YAML/JSON schemas. - Refactored import statements to improve code organization and readability. - Removed redundant import statements from methods. - Enhanced error handling for invalid YAML/JSON schema or file paths.
feat: Add JSONSchema YAML support to Agentfile output format
Reviewer's GuideThis PR introduces full YAML Agentfile support with auto-detection and conversion utilities, enriches the CLI with explicit format flags and new convert/validate commands, implements environment variable expansion in parsing, refactors list handling in code generation for consistency, updates documentation and examples for both Dockerfile and YAML formats, and expands test coverage and CI workflows to validate the new capabilities. Sequence diagram for CLI build/run with format detection and environment variable expansionsequenceDiagram
actor User
participant CLI as agentman CLI
participant Parser as AgentfileParser/YamlParser
participant Builder as AgentBuilder
participant OS as OS/Env
User->>CLI: agentman build/run [--format/--from-yaml] .
CLI->>Parser: parse_file(agentfile_path, format_hint)
Parser->>OS: Read Agentfile/Agentfile.yml
Parser->>OS: Expand environment variables in values
Parser-->>CLI: AgentfileConfig
CLI->>Builder: build_all(AgentfileConfig)
Builder->>OS: Generate agent files
Builder-->>CLI: Build complete
CLI-->>User: Success message
ER diagram for Agentfile YAML structureerDiagram
AGENTFILE {
string apiVersion
string kind
}
AGENT {
string name
string instruction
string model
boolean use_history
boolean human_input
boolean default
OutputFormat output_format
}
MCP_SERVER {
string name
string command
string[] args
string transport
string url
map env
}
AGENTFILE ||--o{ AGENT : agents
AGENTFILE ||--o{ MCP_SERVER : mcp_servers
AGENT }o--|| OutputFormat : output_format
Class diagram for AgentfileParser, AgentfileYamlParser, and OutputFormatclassDiagram
class AgentfileParser {
+AgentfileConfig config
+parse_file(filepath)
+parse_content(content)
}
class AgentfileYamlParser {
+AgentfileConfig config
+parse_file(filepath)
+parse_content(content)
}
class OutputFormat {
+str type
+Dict schema
+str file
}
class Agent {
+str name
+str instruction
+List servers
+str model
+bool use_history
+bool human_input
+bool default
+OutputFormat output_format
+to_decorator_string(...)
}
AgentfileParser --|> AgentfileYamlParser : format auto-detection
Agent "1" -- "0..1" OutputFormat : output_format
Class diagram for CLI subcommands and conversion utilitiesclassDiagram
class CLI {
+build_cli(args)
+run_cli(args)
+convert_cli(args)
+validate_cli(args)
}
class Converter {
+convert_agentfile(input, output, target_format)
+dockerfile_to_yaml(...)
+yaml_to_dockerfile(...)
+validate_agentfile(...)
}
CLI ..> Converter : uses
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @AgentO3 - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `src/agentman/agentfile_parser.py:125` </location>
<code_context>
+ if not self.output_format:
+ return None
+
+ if self.output_format.type == "json_schema" and self.output_format.schema:
+ # Convert JSON Schema to OpenAI response_format structure
+ schema = self.output_format.schema
+ model_name = self._get_model_name_from_schema(schema)
+
+ response_format = {"type": "json_schema", "json_schema": {"name": model_name, "schema": schema}}
+
+ return f"RequestParams(response_format={response_format})"
</code_context>
<issue_to_address>
Directly embedding Python dicts in generated code may cause syntax issues.
Embedding the dictionary directly may result in invalid Python if the schema is complex. Use serialization (e.g., `json.dumps`) or a safer code generation method to ensure valid output.
</issue_to_address>
### Comment 2
<location> `src/agentman/agentfile_parser.py:134` </location>
<code_context>
+
+ return f"RequestParams(response_format={response_format})"
+
+ if self.output_format.type == "schema_file" and self.output_format.file:
+ # Load and convert external schema file
+ return self._generate_request_params_from_file(base_path)
+
+ return None
</code_context>
<issue_to_address>
No error handling for missing or unreadable schema files in generated code.
Consider raising an exception or adding a fallback to prevent silent failures when the schema file is missing or unreadable, as a comment in the generated code may not be sufficient for downstream users.
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
if self.output_format.type == "schema_file" and self.output_format.file:
# Load and convert external schema file
return self._generate_request_params_from_file(base_path)
return None
=======
if self.output_format.type == "schema_file" and self.output_format.file:
# Load and convert external schema file with error handling
try:
return self._generate_request_params_from_file(base_path)
except (FileNotFoundError, OSError) as e:
raise RuntimeError(
f"Failed to load schema file '{self.output_format.file}': {e}"
) from e
return None
>>>>>>> REPLACE
</suggested_fix>
### Comment 3
<location> `src/agentman/cli.py:332` </location>
<code_context>
parser.set_defaults(func=print_version)
+def convert_cli(args):
+ """Convert between Agentfile formats."""
+ try:
+ target_format = args.format if args.format else "auto"
+ convert_agentfile(args.input, args.output, target_format)
+ except (FileNotFoundError, ValueError) as e:
+ perror(f"Conversion failed: {e}")
+ sys.exit(1)
</code_context>
<issue_to_address>
Error handling in convert_cli may mask unexpected exceptions.
Other exceptions, such as YAML parsing errors, may cause the program to crash without a clear message. Consider handling unexpected exceptions to improve user experience.
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
def convert_cli(args):
"""Convert between Agentfile formats."""
try:
target_format = args.format if args.format else "auto"
convert_agentfile(args.input, args.output, target_format)
except (FileNotFoundError, ValueError) as e:
perror(f"Conversion failed: {e}")
sys.exit(1)
=======
def convert_cli(args):
"""Convert between Agentfile formats."""
try:
target_format = args.format if args.format else "auto"
convert_agentfile(args.input, args.output, target_format)
except (FileNotFoundError, ValueError) as e:
perror(f"Conversion failed: {e}")
sys.exit(1)
except Exception as e:
perror(f"An unexpected error occurred during conversion: {e}")
sys.exit(1)
>>>>>>> REPLACE
</suggested_fix>
### Comment 4
<location> `src/agentman/agent_builder.py:235` </location>
<code_context>
"""Build agent files from an Agentfile."""
- parser = AgentfileParser()
- config = parser.parse_file(agentfile_path)
+ if format_hint == "yaml":
+ parser = AgentfileYamlParser()
+ config = parser.parse_file(agentfile_path)
+ elif format_hint == "dockerfile":
+ parser = AgentfileParser()
+ config = parser.parse_file(agentfile_path)
+ else:
+ # Auto-detect format
+ config = parse_agentfile(agentfile_path)
# Extract source directory from agentfile path
</code_context>
<issue_to_address>
Format detection logic may be ambiguous if both --format and --from-yaml are provided.
Clarify which option takes precedence or add a user warning when both are set to prevent ambiguity.
</issue_to_address>
### Comment 5
<location> `tests/test_yaml_parser.py:69` </location>
<code_context>
+ def test_parse_content_with_mcp_servers(self):
</code_context>
<issue_to_address>
Add test for environment variable expansion in MCP server env.
Please include a test that sets an environment variable and checks that it is correctly expanded in the MCP server's environment dictionary.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| if self.output_format.type == "json_schema" and self.output_format.schema: | ||
| # Convert JSON Schema to OpenAI response_format structure | ||
| schema = self.output_format.schema | ||
| model_name = self._get_model_name_from_schema(schema) | ||
|
|
||
| response_format = {"type": "json_schema", "json_schema": {"name": model_name, "schema": schema}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (bug_risk): Directly embedding Python dicts in generated code may cause syntax issues.
Embedding the dictionary directly may result in invalid Python if the schema is complex. Use serialization (e.g., json.dumps) or a safer code generation method to ensure valid output.
| if self.output_format.type == "schema_file" and self.output_format.file: | ||
| # Load and convert external schema file | ||
| return self._generate_request_params_from_file(base_path) | ||
|
|
||
| return None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (bug_risk): No error handling for missing or unreadable schema files in generated code.
Consider raising an exception or adding a fallback to prevent silent failures when the schema file is missing or unreadable, as a comment in the generated code may not be sufficient for downstream users.
| if self.output_format.type == "schema_file" and self.output_format.file: | |
| # Load and convert external schema file | |
| return self._generate_request_params_from_file(base_path) | |
| return None | |
| if self.output_format.type == "schema_file" and self.output_format.file: | |
| # Load and convert external schema file with error handling | |
| try: | |
| return self._generate_request_params_from_file(base_path) | |
| except (FileNotFoundError, OSError) as e: | |
| raise RuntimeError( | |
| f"Failed to load schema file '{self.output_format.file}': {e}" | |
| ) from e | |
| return None |
| def convert_cli(args): | ||
| """Convert between Agentfile formats.""" | ||
| try: | ||
| target_format = args.format if args.format else "auto" | ||
| convert_agentfile(args.input, args.output, target_format) | ||
| except (FileNotFoundError, ValueError) as e: | ||
| perror(f"Conversion failed: {e}") | ||
| sys.exit(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (bug_risk): Error handling in convert_cli may mask unexpected exceptions.
Other exceptions, such as YAML parsing errors, may cause the program to crash without a clear message. Consider handling unexpected exceptions to improve user experience.
| def convert_cli(args): | |
| """Convert between Agentfile formats.""" | |
| try: | |
| target_format = args.format if args.format else "auto" | |
| convert_agentfile(args.input, args.output, target_format) | |
| except (FileNotFoundError, ValueError) as e: | |
| perror(f"Conversion failed: {e}") | |
| sys.exit(1) | |
| def convert_cli(args): | |
| """Convert between Agentfile formats.""" | |
| try: | |
| target_format = args.format if args.format else "auto" | |
| convert_agentfile(args.input, args.output, target_format) | |
| except (FileNotFoundError, ValueError) as e: | |
| perror(f"Conversion failed: {e}") | |
| sys.exit(1) | |
| except Exception as e: | |
| perror(f"An unexpected error occurred during conversion: {e}") | |
| sys.exit(1) |
| if format_hint == "yaml": | ||
| parser = AgentfileYamlParser() | ||
| config = parser.parse_file(agentfile_path) | ||
| elif format_hint == "dockerfile": | ||
| parser = AgentfileParser() | ||
| config = parser.parse_file(agentfile_path) | ||
| else: | ||
| # Auto-detect format | ||
| config = parse_agentfile(agentfile_path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: Format detection logic may be ambiguous if both --format and --from-yaml are provided.
Clarify which option takes precedence or add a user warning when both are set to prevent ambiguity.
| def test_parse_content_with_mcp_servers(self): | ||
| """Test parsing YAML with MCP servers.""" | ||
| content = """ | ||
| apiVersion: v1 | ||
| kind: Agent | ||
| mcp_servers: | ||
| - name: filesystem | ||
| command: uv | ||
| args: [tool, run, mcp-server-filesystem, /tmp] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (testing): Add test for environment variable expansion in MCP server env.
Please include a test that sets an environment variable and checks that it is correctly expanded in the MCP server's environment dictionary.
| path = Path(filepath) | ||
|
|
||
| # Check file extension | ||
| if path.suffix.lower() in ['.yml', '.yaml']: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (code-quality): We've found these issues:
- Use set when checking membership of a collection of literals (
collection-into-set) - Lift code into else after jump in control flow (
reintroduce-else) - Replace if statement with if expression (
assign-if-exp) - Simplify boolean if expression (
boolean-if-exp-identity) - Remove unnecessary casts to int, str, float or bool (
remove-unnecessary-cast)
| fs_server = config.servers["filesystem"] | ||
| assert fs_server.name == "filesystem" | ||
| assert fs_server.command == "uv" | ||
| assert fs_server.args == ["tool", "run", "mcp-server-filesystem", "/tmp"] | ||
| assert fs_server.transport == "stdio" | ||
| assert fs_server.env == {"PATH": "/usr/local/bin", "DEBUG": "true"} | ||
|
|
||
| web_server = config.servers["web_search"] | ||
| assert web_server.name == "web_search" | ||
| assert web_server.command == "uvx" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (code-quality): Extract duplicate code into method (extract-duplicate-method)
| inline_secret = config.secrets[1] | ||
| assert isinstance(inline_secret, SecretValue) | ||
| assert inline_secret.name == "INLINE_SECRET" | ||
| assert inline_secret.value == "secret-value-123" | ||
|
|
||
| # Secret context | ||
| context_secret = config.secrets[2] | ||
| assert isinstance(context_secret, SecretContext) | ||
| assert context_secret.name == "OPENAI_CONFIG" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (code-quality): Extract duplicate code into method (extract-duplicate-method)
| def test_detect_yaml_format_by_extension(self): | ||
| """Test detecting YAML format by file extension.""" | ||
| with tempfile.NamedTemporaryFile(mode='w', suffix='.yml', delete=False) as f: | ||
| f.write("apiVersion: v1\nkind: Agent\n") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (code-quality): Extract duplicate code into method (extract-duplicate-method)
| name: test_agent | ||
| """ | ||
| with tempfile.NamedTemporaryFile(mode='w', suffix='.yml', delete=False) as f: | ||
| f.write(yaml_content) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (code-quality): Extract duplicate code into method [×2] (extract-duplicate-method)
This commit introduces a new GitHub Actions workflow to automate the building and pushing of Docker images. The workflow triggers on pushes and pull requests to the main branch, specifically when changes are made to the Dockerfile or the workflow file itself. It uses GitHub's Container Registry for storing images and supports multi-platform builds for amd64 and arm64 architectures.
Summary by Sourcery
Add YAML Agentfile support with auto-detection, structured output validation via JSONSchema and external schema files, environment variable expansion, and CLI enhancements for conversion and validation. Update documentation with examples for both Dockerfile and YAML formats, introduce extensive tests for new features, and configure CI workflows.
New Features:
Enhancements:
CI:
Documentation:
Tests:
Chores: