Skip to content
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
29 changes: 29 additions & 0 deletions .cursor/rules/workflow-branch-pr.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
description: Never commit directly to main; use issues, branch, fix, test, PR
alwaysApply: true
---

# Workflow: Issues, Branch, PR

**Never make changes or commits directly on `main`.**

For every bug or feature:

1. **Document in GitHub**
Create or reference an issue in the project’s GitHub repo (bug report or feature request).

2. **Create a branch**
From `main` (or `develop` if the project uses Git Flow):
`feature/*`, `bugfix/*`, `fix/*`, or `release/vX.Y.Z` as appropriate.

3. **Implement and test**
Do all edits and commits on that branch. Run the test suite (`uv run pytest`) and fix any failures.

4. **Push and open a PR**
Push the branch and open a Pull Request targeting `main` (or `develop`).
Link the PR to the issue (e.g. “Fixes #123”).

5. **Merge after review**
Do not merge yourself unless the project allows it; wait for review/approval if required.

For hotfixes or release bumps, use a dedicated branch (e.g. `fix/description` or `release/0.9.1`) and follow the same flow.
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
- New features and fixes should include or update tests; no explicit coverage target is defined.

## Commit & Pull Request Guidelines
- Follow Git Flow: branch from `develop` and PR back to `develop`.
- Branch names: `feature/*`, `bugfix/*`, `release/vX.Y.Z`, `hotfix/*`.
- **Do not commit directly to `main`.** For every change: document in a GitHub issue → create a branch → implement → test → push → open a PR. See `.cursor/rules/workflow-branch-pr.mdc`.
- Follow Git Flow: branch from `develop` (or `main`) and PR back to `develop`/`main`.
- Branch names: `feature/*`, `bugfix/*`, `fix/*`, `release/vX.Y.Z`, `hotfix/*`.
- Commit messages use `type: short description` (e.g., `feat: add streaming API endpoint`).
- PRs should include a clear description, pass tests, and update docs when needed.

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ ARG INSTALL_LATEX=false

# Labels
LABEL maintainer="DSAgent Contributors"
LABEL version="0.9.0"
LABEL version="0.9.1"
LABEL description="AI-powered autonomous agent for data science"

# Set environment variables
Expand Down
2 changes: 1 addition & 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 = "datascience-agent"
version = "0.9.0"
version = "0.9.1"
description = "AI Agent with dynamic planning and persistent Jupyter kernel execution for data analysis"
readme = "README.md"
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion src/dsagent/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
MCPServerConfig = None # type: ignore
_MCP_AVAILABLE = False

__version__ = "0.9.0"
__version__ = "0.9.1"

__all__ = [
# Main classes
Expand Down
11 changes: 7 additions & 4 deletions src/dsagent/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,12 @@ def main():

args = parser.parse_args()

# Validate model and API key configuration
# Resolve model (CLI flag, env, or fallback) before validation
from dsagent.config import get_default_model
effective_model = get_default_model(explicit=args.model)

try:
validate_configuration(args.model)
validate_configuration(effective_model)
except ConfigurationError as e:
print(f"Configuration Error: {e}", file=sys.stderr)
sys.exit(1)
Expand Down Expand Up @@ -189,7 +192,7 @@ def main():
if data_info:
print(f"Data: {data_info}")
print(f"Run Path: {context.run_path}")
print(f"Model: {args.model}")
print(f"Model: {effective_model}")
if hitl_mode != HITLMode.NONE:
print(f"HITL Mode: {hitl_mode.value}")
if mcp_config_path:
Expand All @@ -209,7 +212,7 @@ def main():

# Create and run agent with context
agent = PlannerAgent(
model=args.model,
model=effective_model,
workspace=context.run_path, # Use run-specific path
max_rounds=args.max_rounds,
verbose=not args.quiet,
Expand Down
20 changes: 13 additions & 7 deletions src/dsagent/cli/repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -671,10 +671,13 @@ def main():

args = parser.parse_args()

# Validate configuration
# Resolve model (CLI flag, env, or fallback) before validation
from dsagent.config import get_default_model
from dsagent.utils.validation import validate_configuration
effective_model = get_default_model(explicit=args.model)

try:
from dsagent.utils.validation import validate_configuration
validate_configuration(args.model)
validate_configuration(effective_model)
except Exception as e:
console = Console()
console.print(f"[red]Configuration Error: {e}[/red]")
Expand Down Expand Up @@ -702,7 +705,7 @@ def main():
# Run the CLI
cli = ConversationalCLI(
workspace=Path(args.workspace),
model=args.model,
model=effective_model,
session_id=args.session,
hitl_mode=hitl_mode,
enable_live_notebook=args.live_notebook,
Expand All @@ -727,13 +730,16 @@ def run_chat(args) -> int:
Returns:
Exit code (0 for success)
"""
from dsagent.config import get_default_model
from dsagent.utils.validation import validate_configuration

console = Console()

# Validate configuration
# Resolve model (CLI flag, env, or fallback) before validation
effective_model = get_default_model(explicit=args.model)

try:
validate_configuration(args.model)
validate_configuration(effective_model)
except Exception as e:
console.print(f"[red]Configuration Error: {e}[/red]")
return 1
Expand All @@ -759,7 +765,7 @@ def run_chat(args) -> int:
# Run the CLI
cli = ConversationalCLI(
workspace=Path(args.workspace),
model=args.model,
model=effective_model,
session_id=getattr(args, 'session', None),
hitl_mode=hitl_mode,
enable_live_notebook=getattr(args, 'live_notebook', False),
Expand Down
11 changes: 7 additions & 4 deletions src/dsagent/cli/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,12 @@ def run_task(args) -> int:
"""
console = Console()

# Validate model configuration
# Resolve model (CLI flag, env, or fallback) before validation
from dsagent.config import get_default_model
effective_model = get_default_model(explicit=args.model)

try:
validate_configuration(args.model)
validate_configuration(effective_model)
except ConfigurationError as e:
console.print(f"[red]Configuration Error: {e}[/red]")
return 1
Expand Down Expand Up @@ -91,7 +94,7 @@ def run_task(args) -> int:
if data_info:
console.print(f"[cyan]Data:[/cyan] {data_info}")
console.print(f"[cyan]Run Path:[/cyan] {context.run_path}")
console.print(f"[cyan]Model:[/cyan] {args.model}")
console.print(f"[cyan]Model:[/cyan] {effective_model}")
if hitl_mode != HITLMode.NONE:
console.print(f"[cyan]HITL Mode:[/cyan] {hitl_mode.value}")
if mcp_config_path:
Expand All @@ -111,7 +114,7 @@ def run_task(args) -> int:

# Create and run agent
agent = PlannerAgent(
model=args.model,
model=effective_model,
workspace=context.run_path,
max_rounds=args.max_rounds,
verbose=not args.quiet,
Expand Down
10 changes: 8 additions & 2 deletions src/dsagent/utils/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,15 +238,21 @@ def validate_model_name(model: str) -> None:
)


def validate_configuration(model: str) -> None:
def validate_configuration(model: Optional[str]) -> None:
"""Validate all configuration for running with the given model.

Args:
model: The model name/identifier
model: The model name/identifier (must be non-empty; use get_default_model()
before calling if the value can be None)

Raises:
ConfigurationError: If any configuration is invalid
"""
if not model or not isinstance(model, str):
raise ConfigurationError(
"Model name must be set. Use DSAGENT_DEFAULT_MODEL or LLM_MODEL, "
"or pass --model. Run 'dsagent init' to configure."
)
apply_llm_api_base(model)
# validate_model_name(model)
validate_api_key(model)
4 changes: 2 additions & 2 deletions tests/test_conversational.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ class TestConversationalAgentConfig:
"""Tests for ConversationalAgentConfig."""

def test_default_config(self):
"""Test default configuration values."""
"""Test default configuration values. Model is resolved at runtime via get_default_model()."""
config = ConversationalAgentConfig()

assert config.model == "gpt-4o"
assert config.model is None # resolved at runtime
assert config.temperature == 0.3
assert config.max_tokens == 4096
assert config.code_timeout == 300
Expand Down