titan-cli 0.1.0__py3-none-any.whl
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.
- titan_cli/__init__.py +3 -0
- titan_cli/__main__.py +4 -0
- titan_cli/ai/__init__.py +0 -0
- titan_cli/ai/agents/__init__.py +15 -0
- titan_cli/ai/agents/base.py +152 -0
- titan_cli/ai/client.py +170 -0
- titan_cli/ai/constants.py +56 -0
- titan_cli/ai/exceptions.py +48 -0
- titan_cli/ai/models.py +34 -0
- titan_cli/ai/oauth_helper.py +120 -0
- titan_cli/ai/providers/__init__.py +9 -0
- titan_cli/ai/providers/anthropic.py +117 -0
- titan_cli/ai/providers/base.py +75 -0
- titan_cli/ai/providers/gemini.py +278 -0
- titan_cli/cli.py +59 -0
- titan_cli/clients/__init__.py +1 -0
- titan_cli/clients/gcloud_client.py +52 -0
- titan_cli/core/__init__.py +3 -0
- titan_cli/core/config.py +274 -0
- titan_cli/core/discovery.py +51 -0
- titan_cli/core/errors.py +81 -0
- titan_cli/core/models.py +52 -0
- titan_cli/core/plugins/available.py +36 -0
- titan_cli/core/plugins/models.py +67 -0
- titan_cli/core/plugins/plugin_base.py +108 -0
- titan_cli/core/plugins/plugin_registry.py +163 -0
- titan_cli/core/secrets.py +141 -0
- titan_cli/core/workflows/__init__.py +22 -0
- titan_cli/core/workflows/models.py +88 -0
- titan_cli/core/workflows/project_step_source.py +86 -0
- titan_cli/core/workflows/workflow_exceptions.py +17 -0
- titan_cli/core/workflows/workflow_filter_service.py +137 -0
- titan_cli/core/workflows/workflow_registry.py +419 -0
- titan_cli/core/workflows/workflow_sources.py +307 -0
- titan_cli/engine/__init__.py +39 -0
- titan_cli/engine/builder.py +159 -0
- titan_cli/engine/context.py +82 -0
- titan_cli/engine/mock_context.py +176 -0
- titan_cli/engine/results.py +91 -0
- titan_cli/engine/steps/ai_assistant_step.py +185 -0
- titan_cli/engine/steps/command_step.py +93 -0
- titan_cli/engine/utils/__init__.py +3 -0
- titan_cli/engine/utils/venv.py +31 -0
- titan_cli/engine/workflow_executor.py +187 -0
- titan_cli/external_cli/__init__.py +0 -0
- titan_cli/external_cli/configs.py +17 -0
- titan_cli/external_cli/launcher.py +65 -0
- titan_cli/messages.py +121 -0
- titan_cli/ui/tui/__init__.py +205 -0
- titan_cli/ui/tui/__previews__/statusbar_preview.py +88 -0
- titan_cli/ui/tui/app.py +113 -0
- titan_cli/ui/tui/icons.py +70 -0
- titan_cli/ui/tui/screens/__init__.py +24 -0
- titan_cli/ui/tui/screens/ai_config.py +498 -0
- titan_cli/ui/tui/screens/ai_config_wizard.py +882 -0
- titan_cli/ui/tui/screens/base.py +110 -0
- titan_cli/ui/tui/screens/cli_launcher.py +151 -0
- titan_cli/ui/tui/screens/global_setup_wizard.py +363 -0
- titan_cli/ui/tui/screens/main_menu.py +162 -0
- titan_cli/ui/tui/screens/plugin_config_wizard.py +550 -0
- titan_cli/ui/tui/screens/plugin_management.py +377 -0
- titan_cli/ui/tui/screens/project_setup_wizard.py +686 -0
- titan_cli/ui/tui/screens/workflow_execution.py +592 -0
- titan_cli/ui/tui/screens/workflows.py +249 -0
- titan_cli/ui/tui/textual_components.py +537 -0
- titan_cli/ui/tui/textual_workflow_executor.py +405 -0
- titan_cli/ui/tui/theme.py +102 -0
- titan_cli/ui/tui/widgets/__init__.py +40 -0
- titan_cli/ui/tui/widgets/button.py +108 -0
- titan_cli/ui/tui/widgets/header.py +116 -0
- titan_cli/ui/tui/widgets/panel.py +81 -0
- titan_cli/ui/tui/widgets/status_bar.py +115 -0
- titan_cli/ui/tui/widgets/table.py +77 -0
- titan_cli/ui/tui/widgets/text.py +177 -0
- titan_cli/utils/__init__.py +0 -0
- titan_cli/utils/autoupdate.py +155 -0
- titan_cli-0.1.0.dist-info/METADATA +149 -0
- titan_cli-0.1.0.dist-info/RECORD +146 -0
- titan_cli-0.1.0.dist-info/WHEEL +4 -0
- titan_cli-0.1.0.dist-info/entry_points.txt +9 -0
- titan_cli-0.1.0.dist-info/licenses/LICENSE +201 -0
- titan_plugin_git/__init__.py +1 -0
- titan_plugin_git/clients/__init__.py +8 -0
- titan_plugin_git/clients/git_client.py +772 -0
- titan_plugin_git/exceptions.py +40 -0
- titan_plugin_git/messages.py +112 -0
- titan_plugin_git/models.py +39 -0
- titan_plugin_git/plugin.py +118 -0
- titan_plugin_git/steps/__init__.py +1 -0
- titan_plugin_git/steps/ai_commit_message_step.py +171 -0
- titan_plugin_git/steps/branch_steps.py +104 -0
- titan_plugin_git/steps/commit_step.py +80 -0
- titan_plugin_git/steps/push_step.py +63 -0
- titan_plugin_git/steps/status_step.py +59 -0
- titan_plugin_git/workflows/__previews__/__init__.py +1 -0
- titan_plugin_git/workflows/__previews__/commit_ai_preview.py +124 -0
- titan_plugin_git/workflows/commit-ai.yaml +28 -0
- titan_plugin_github/__init__.py +11 -0
- titan_plugin_github/agents/__init__.py +6 -0
- titan_plugin_github/agents/config_loader.py +130 -0
- titan_plugin_github/agents/issue_generator.py +353 -0
- titan_plugin_github/agents/pr_agent.py +528 -0
- titan_plugin_github/clients/__init__.py +8 -0
- titan_plugin_github/clients/github_client.py +1105 -0
- titan_plugin_github/config/__init__.py +0 -0
- titan_plugin_github/config/pr_agent.toml +85 -0
- titan_plugin_github/exceptions.py +28 -0
- titan_plugin_github/messages.py +88 -0
- titan_plugin_github/models.py +330 -0
- titan_plugin_github/plugin.py +131 -0
- titan_plugin_github/steps/__init__.py +12 -0
- titan_plugin_github/steps/ai_pr_step.py +172 -0
- titan_plugin_github/steps/create_pr_step.py +86 -0
- titan_plugin_github/steps/github_prompt_steps.py +171 -0
- titan_plugin_github/steps/issue_steps.py +143 -0
- titan_plugin_github/steps/preview_step.py +40 -0
- titan_plugin_github/utils.py +82 -0
- titan_plugin_github/workflows/__previews__/__init__.py +1 -0
- titan_plugin_github/workflows/__previews__/create_pr_ai_preview.py +140 -0
- titan_plugin_github/workflows/create-issue-ai.yaml +32 -0
- titan_plugin_github/workflows/create-pr-ai.yaml +49 -0
- titan_plugin_jira/__init__.py +8 -0
- titan_plugin_jira/agents/__init__.py +6 -0
- titan_plugin_jira/agents/config_loader.py +154 -0
- titan_plugin_jira/agents/jira_agent.py +553 -0
- titan_plugin_jira/agents/prompts.py +364 -0
- titan_plugin_jira/agents/response_parser.py +435 -0
- titan_plugin_jira/agents/token_tracker.py +223 -0
- titan_plugin_jira/agents/validators.py +246 -0
- titan_plugin_jira/clients/jira_client.py +745 -0
- titan_plugin_jira/config/jira_agent.toml +92 -0
- titan_plugin_jira/config/templates/issue_analysis.md.j2 +78 -0
- titan_plugin_jira/exceptions.py +37 -0
- titan_plugin_jira/formatters/__init__.py +6 -0
- titan_plugin_jira/formatters/markdown_formatter.py +245 -0
- titan_plugin_jira/messages.py +115 -0
- titan_plugin_jira/models.py +89 -0
- titan_plugin_jira/plugin.py +264 -0
- titan_plugin_jira/steps/ai_analyze_issue_step.py +105 -0
- titan_plugin_jira/steps/get_issue_step.py +82 -0
- titan_plugin_jira/steps/prompt_select_issue_step.py +80 -0
- titan_plugin_jira/steps/search_saved_query_step.py +238 -0
- titan_plugin_jira/utils/__init__.py +13 -0
- titan_plugin_jira/utils/issue_sorter.py +140 -0
- titan_plugin_jira/utils/saved_queries.py +150 -0
- titan_plugin_jira/workflows/analyze-jira-issues.yaml +34 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Create PR with AI Workflow Preview
|
|
4
|
+
|
|
5
|
+
Preview the create-pr-ai workflow by executing real steps with mocked data.
|
|
6
|
+
Run: titan preview workflow create-pr-ai
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from titan_cli.ui.components.typography import TextRenderer
|
|
10
|
+
from titan_cli.ui.components.spacer import SpacerRenderer
|
|
11
|
+
from titan_cli.engine.mock_context import (
|
|
12
|
+
MockGitClient,
|
|
13
|
+
MockAIClient,
|
|
14
|
+
MockGitHubClient,
|
|
15
|
+
MockSecretManager,
|
|
16
|
+
)
|
|
17
|
+
from titan_cli.engine import WorkflowContext
|
|
18
|
+
from titan_cli.engine.ui_container import UIComponents
|
|
19
|
+
from titan_cli.engine.views_container import UIViews
|
|
20
|
+
from titan_cli.engine.results import Success, Error, Skip
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def create_create_pr_ai_mock_context() -> WorkflowContext:
|
|
24
|
+
"""
|
|
25
|
+
Create mock context specifically for create-pr-ai workflow.
|
|
26
|
+
|
|
27
|
+
Customizes mock data to simulate the create-pr-ai workflow scenario:
|
|
28
|
+
- Git status with uncommitted changes
|
|
29
|
+
- AI generates commit message and PR description
|
|
30
|
+
- GitHub creates PR on feature branch
|
|
31
|
+
|
|
32
|
+
Pre-populates context data to ensure all steps execute successfully
|
|
33
|
+
and display their full UI in the preview.
|
|
34
|
+
"""
|
|
35
|
+
# Create UI components
|
|
36
|
+
ui = UIComponents.create()
|
|
37
|
+
views = UIViews.create(ui)
|
|
38
|
+
|
|
39
|
+
# Override prompts to auto-confirm (non-interactive preview)
|
|
40
|
+
views.prompts.ask_confirm = lambda question, default=True: True
|
|
41
|
+
|
|
42
|
+
# Create mock clients with workflow-specific data
|
|
43
|
+
git = MockGitClient()
|
|
44
|
+
git.current_branch = "feat/workflow-preview"
|
|
45
|
+
git.main_branch = "master"
|
|
46
|
+
git.default_remote = "origin"
|
|
47
|
+
|
|
48
|
+
ai = MockAIClient()
|
|
49
|
+
|
|
50
|
+
github = MockGitHubClient()
|
|
51
|
+
github.repo_owner = "mockuser"
|
|
52
|
+
github.repo_name = "titan-cli"
|
|
53
|
+
|
|
54
|
+
secrets = MockSecretManager()
|
|
55
|
+
|
|
56
|
+
# Build context
|
|
57
|
+
ctx = WorkflowContext(
|
|
58
|
+
secrets=secrets,
|
|
59
|
+
ui=ui,
|
|
60
|
+
views=views
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# Inject mocked clients
|
|
64
|
+
ctx.git = git
|
|
65
|
+
ctx.ai = ai
|
|
66
|
+
ctx.github = github
|
|
67
|
+
|
|
68
|
+
# Pre-populate initial data for complete workflow execution
|
|
69
|
+
# This simulates data that would come from command-line or earlier setup
|
|
70
|
+
ctx.set("base_branch", "master")
|
|
71
|
+
ctx.set("draft", False)
|
|
72
|
+
|
|
73
|
+
return ctx
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def preview_workflow():
|
|
77
|
+
"""
|
|
78
|
+
Preview the create-pr-ai workflow by executing real steps with mocked context.
|
|
79
|
+
|
|
80
|
+
This ensures the preview always matches the real workflow execution.
|
|
81
|
+
"""
|
|
82
|
+
text = TextRenderer()
|
|
83
|
+
spacer = SpacerRenderer()
|
|
84
|
+
|
|
85
|
+
# Header
|
|
86
|
+
text.title("Create Pull Request with AI - PREVIEW")
|
|
87
|
+
text.subtitle("(Executing real steps with mocked data)")
|
|
88
|
+
spacer.line()
|
|
89
|
+
|
|
90
|
+
# Create workflow-specific mock context
|
|
91
|
+
ctx = create_create_pr_ai_mock_context()
|
|
92
|
+
|
|
93
|
+
# Import steps
|
|
94
|
+
from titan_plugin_git.steps.status_step import get_git_status_step
|
|
95
|
+
from titan_plugin_git.steps.ai_commit_message_step import ai_generate_commit_message
|
|
96
|
+
from titan_plugin_git.steps.commit_step import create_git_commit_step
|
|
97
|
+
from titan_plugin_git.steps.push_step import create_git_push_step
|
|
98
|
+
from titan_plugin_github.steps.ai_pr_step import ai_suggest_pr_description_step
|
|
99
|
+
from titan_plugin_github.steps.prompt_steps import prompt_for_pr_title_step, prompt_for_pr_body_step
|
|
100
|
+
|
|
101
|
+
# Execute steps in order
|
|
102
|
+
steps = [
|
|
103
|
+
("git_status", get_git_status_step),
|
|
104
|
+
("ai_commit_message", ai_generate_commit_message),
|
|
105
|
+
("create_commit", create_git_commit_step),
|
|
106
|
+
("push", create_git_push_step),
|
|
107
|
+
("ai_pr_description", ai_suggest_pr_description_step),
|
|
108
|
+
("prompt_pr_title", prompt_for_pr_title_step),
|
|
109
|
+
("prompt_pr_body", prompt_for_pr_body_step),
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
text.info("Executing workflow...")
|
|
113
|
+
spacer.small()
|
|
114
|
+
|
|
115
|
+
# Inject workflow metadata (like the real executor does)
|
|
116
|
+
ctx.workflow_name = "create-pr-ai"
|
|
117
|
+
ctx.total_steps = len(steps)
|
|
118
|
+
|
|
119
|
+
for i, (step_name, step_fn) in enumerate(steps, 1):
|
|
120
|
+
# Inject current step number (like the real executor does)
|
|
121
|
+
ctx.current_step = i
|
|
122
|
+
|
|
123
|
+
# Execute the step - it will handle all its own UI
|
|
124
|
+
result = step_fn(ctx)
|
|
125
|
+
|
|
126
|
+
# Merge metadata into context (like the real executor does)
|
|
127
|
+
if isinstance(result, (Success, Skip)) and result.metadata:
|
|
128
|
+
ctx.data.update(result.metadata)
|
|
129
|
+
|
|
130
|
+
# Only handle errors (steps handle their own success/skip UI)
|
|
131
|
+
if isinstance(result, Error):
|
|
132
|
+
text.error(f"Step '{step_name}' failed: {result.message}")
|
|
133
|
+
break
|
|
134
|
+
|
|
135
|
+
spacer.line()
|
|
136
|
+
text.info("(This was a preview - no actual git/GitHub operations were performed)")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
if __name__ == "__main__":
|
|
140
|
+
preview_workflow()
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: "Create GitHub Issue (AI-Powered)"
|
|
2
|
+
description: "Create a GitHub issue with AI-generated description and auto-categorization"
|
|
3
|
+
params:
|
|
4
|
+
assignees: []
|
|
5
|
+
steps:
|
|
6
|
+
- id: prompt_for_issue_body
|
|
7
|
+
name: "Prompt for Issue Body"
|
|
8
|
+
plugin: github
|
|
9
|
+
step: prompt_for_issue_body_step
|
|
10
|
+
|
|
11
|
+
- id: ai_suggest_issue
|
|
12
|
+
name: "Categorize and Generate Issue"
|
|
13
|
+
plugin: github
|
|
14
|
+
step: ai_suggest_issue_title_and_body
|
|
15
|
+
|
|
16
|
+
- id: preview_and_confirm_issue
|
|
17
|
+
name: "Preview and Confirm Issue"
|
|
18
|
+
plugin: github
|
|
19
|
+
step: preview_and_confirm_issue
|
|
20
|
+
|
|
21
|
+
- id: prompt_for_self_assign
|
|
22
|
+
name: "Prompt for Self Assign"
|
|
23
|
+
plugin: github
|
|
24
|
+
step: prompt_for_self_assign
|
|
25
|
+
|
|
26
|
+
- id: create_issue
|
|
27
|
+
name: "Create Issue"
|
|
28
|
+
plugin: github
|
|
29
|
+
step: create_issue
|
|
30
|
+
params:
|
|
31
|
+
assignees: "${assignees}"
|
|
32
|
+
labels: "${labels}"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: "Create Pull Request with AI"
|
|
2
|
+
description: "AI-powered PR creation with intelligent analysis and suggestions"
|
|
3
|
+
|
|
4
|
+
params:
|
|
5
|
+
draft: false
|
|
6
|
+
|
|
7
|
+
hooks:
|
|
8
|
+
- before_push
|
|
9
|
+
- after_pr
|
|
10
|
+
|
|
11
|
+
steps:
|
|
12
|
+
# Use the commit-ai workflow (respects project override for linting/testing)
|
|
13
|
+
- id: commit_changes
|
|
14
|
+
name: "Commit changes with AI"
|
|
15
|
+
workflow: "commit-ai"
|
|
16
|
+
|
|
17
|
+
- id: get_head_branch
|
|
18
|
+
name: "Get Head Branch"
|
|
19
|
+
plugin: git
|
|
20
|
+
step: get_current_branch
|
|
21
|
+
|
|
22
|
+
# AI generates PR title and description from branch commits
|
|
23
|
+
- id: ai_pr_description
|
|
24
|
+
name: "AI PR Description"
|
|
25
|
+
plugin: github
|
|
26
|
+
step: ai_suggest_pr_description
|
|
27
|
+
|
|
28
|
+
- hook: before_push
|
|
29
|
+
|
|
30
|
+
# Fallback to manual prompts if AI was rejected
|
|
31
|
+
- id: prompt_pr_title
|
|
32
|
+
name: "Prompt for PR Title"
|
|
33
|
+
plugin: github
|
|
34
|
+
step: prompt_for_pr_title
|
|
35
|
+
|
|
36
|
+
- id: prompt_pr_body
|
|
37
|
+
name: "Prompt for PR Body"
|
|
38
|
+
plugin: github
|
|
39
|
+
step: prompt_for_pr_body
|
|
40
|
+
|
|
41
|
+
- id: create_pr
|
|
42
|
+
name: "Create Pull Request"
|
|
43
|
+
plugin: github
|
|
44
|
+
step: create_pr
|
|
45
|
+
requires:
|
|
46
|
+
- pr_title
|
|
47
|
+
- pr_head_branch
|
|
48
|
+
|
|
49
|
+
- hook: after_pr
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# plugins/titan-plugin-jira/titan_plugin_jira/agents/config_loader.py
|
|
2
|
+
"""Configuration loader for JIRA Agent."""
|
|
3
|
+
|
|
4
|
+
import tomli
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional, Dict, Any
|
|
7
|
+
from pydantic import BaseModel, Field, ConfigDict
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
# Python 3.9+
|
|
11
|
+
from importlib.resources import files
|
|
12
|
+
except ImportError:
|
|
13
|
+
# Python 3.7-3.8 fallback
|
|
14
|
+
from importlib_resources import files
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class JiraAgentConfig(BaseModel):
|
|
18
|
+
"""JIRA Agent configuration loaded from TOML."""
|
|
19
|
+
|
|
20
|
+
name: str = Field(..., description="Agent name")
|
|
21
|
+
description: str = Field("", description="Agent description")
|
|
22
|
+
version: str = Field("1.0.0", description="Agent version")
|
|
23
|
+
|
|
24
|
+
# Prompts
|
|
25
|
+
requirements_system_prompt: str = Field("", description="System prompt for requirements analysis")
|
|
26
|
+
description_enhancement_prompt: str = Field("", description="System prompt for description enhancement")
|
|
27
|
+
comment_generation_prompt: str = Field("", description="System prompt for comment generation")
|
|
28
|
+
subtask_suggestion_prompt: str = Field("", description="System prompt for subtask suggestion")
|
|
29
|
+
smart_labeling_prompt: str = Field("", description="System prompt for smart labeling")
|
|
30
|
+
|
|
31
|
+
# Limits
|
|
32
|
+
max_description_length: int = Field(5000, ge=0, description="Maximum description length")
|
|
33
|
+
max_subtasks: int = Field(10, ge=1, description="Maximum subtasks to suggest")
|
|
34
|
+
max_comments_to_analyze: int = Field(20, ge=1, description="Maximum comments to analyze")
|
|
35
|
+
max_linked_issues: int = Field(15, ge=1, description="Maximum linked issues to consider")
|
|
36
|
+
|
|
37
|
+
# AI Parameters
|
|
38
|
+
temperature: float = Field(0.7, ge=0.0, le=2.0, description="AI temperature for generation")
|
|
39
|
+
max_tokens: int = Field(2000, ge=1, description="Maximum tokens per AI request")
|
|
40
|
+
|
|
41
|
+
# Features (Active)
|
|
42
|
+
enable_requirement_extraction: bool = Field(True, description="Enable requirement extraction")
|
|
43
|
+
enable_subtasks: bool = Field(True, description="Enable subtask suggestion")
|
|
44
|
+
enable_risk_analysis: bool = Field(True, description="Enable risk analysis")
|
|
45
|
+
enable_dependency_detection: bool = Field(True, description="Enable dependency detection")
|
|
46
|
+
enable_acceptance_criteria: bool = Field(True, description="Enable acceptance criteria generation")
|
|
47
|
+
enable_debug_output: bool = Field(False, description="Enable debug output (logs AI responses)")
|
|
48
|
+
|
|
49
|
+
# Features (Planned - Not Yet Implemented)
|
|
50
|
+
# These flags are reserved for future functionality
|
|
51
|
+
# TODO: Implement Gherkin test generation (PR #74 comment: remove unused flags)
|
|
52
|
+
# enable_gherkin_tests: bool = Field(False, description="Enable Gherkin/BDD test scenario generation")
|
|
53
|
+
# TODO: Implement strict label classification
|
|
54
|
+
# enable_strict_labeling: bool = Field(False, description="Enable strict label classification")
|
|
55
|
+
# TODO: Implement token optimization strategies
|
|
56
|
+
# enable_token_saving: bool = Field(False, description="Enable token optimization strategies")
|
|
57
|
+
|
|
58
|
+
# Formatting
|
|
59
|
+
template: str = Field("", description="Optional Jinja2 template filename for formatting output")
|
|
60
|
+
|
|
61
|
+
# Raw config for custom access
|
|
62
|
+
raw: Dict[str, Any] = Field(default_factory=dict, description="Raw TOML data")
|
|
63
|
+
|
|
64
|
+
model_config = ConfigDict(frozen=False) # Allow mutation for caching
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def load_agent_config(
|
|
68
|
+
agent_name: str = "jira_agent",
|
|
69
|
+
config_dir: Optional[Path] = None
|
|
70
|
+
) -> JiraAgentConfig:
|
|
71
|
+
"""
|
|
72
|
+
Load agent configuration from TOML file.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
agent_name: Name of the agent (e.g., "jira_agent")
|
|
76
|
+
config_dir: Optional custom config directory
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
JiraAgentConfig instance
|
|
80
|
+
|
|
81
|
+
Raises:
|
|
82
|
+
FileNotFoundError: If config file doesn't exist
|
|
83
|
+
ValueError: If config is invalid
|
|
84
|
+
"""
|
|
85
|
+
# Determine config file path
|
|
86
|
+
if config_dir:
|
|
87
|
+
config_path = config_dir / f"{agent_name}.toml"
|
|
88
|
+
else:
|
|
89
|
+
# Use importlib.resources for robust path resolution
|
|
90
|
+
config_files = files("titan_plugin_jira.config")
|
|
91
|
+
config_file = config_files.joinpath(f"{agent_name}.toml")
|
|
92
|
+
|
|
93
|
+
# Convert Traversable to Path
|
|
94
|
+
if hasattr(config_file, "__fspath__"):
|
|
95
|
+
config_path = Path(config_file.__fspath__())
|
|
96
|
+
else:
|
|
97
|
+
config_path = Path(str(config_file))
|
|
98
|
+
|
|
99
|
+
if not config_path.exists():
|
|
100
|
+
raise FileNotFoundError(f"Agent config not found: {config_path}")
|
|
101
|
+
|
|
102
|
+
# Load TOML
|
|
103
|
+
try:
|
|
104
|
+
with open(config_path, "rb") as f:
|
|
105
|
+
data = tomli.load(f)
|
|
106
|
+
except tomli.TOMLDecodeError as e:
|
|
107
|
+
raise ValueError(f"Invalid TOML in {config_path}: {e}")
|
|
108
|
+
except Exception as e:
|
|
109
|
+
raise ValueError(f"Failed to read config {config_path}: {e}")
|
|
110
|
+
|
|
111
|
+
# Validate config structure
|
|
112
|
+
if "agent" not in data:
|
|
113
|
+
raise ValueError(f"Missing [agent] section in {config_path}")
|
|
114
|
+
|
|
115
|
+
# Extract sections
|
|
116
|
+
agent_meta = data.get("agent", {})
|
|
117
|
+
prompts = data.get("agent", {}).get("prompts", {})
|
|
118
|
+
limits = data.get("agent", {}).get("limits", {})
|
|
119
|
+
features = data.get("agent", {}).get("features", {})
|
|
120
|
+
formatting = data.get("agent", {}).get("formatting", {})
|
|
121
|
+
|
|
122
|
+
# Build JiraAgentConfig
|
|
123
|
+
return JiraAgentConfig(
|
|
124
|
+
name=agent_meta.get("name", agent_name),
|
|
125
|
+
description=agent_meta.get("description", ""),
|
|
126
|
+
version=agent_meta.get("version", "1.0.0"),
|
|
127
|
+
# Prompts
|
|
128
|
+
requirements_system_prompt=prompts.get("requirements_analysis", {}).get("system", ""),
|
|
129
|
+
description_enhancement_prompt=prompts.get("description_enhancement", {}).get("system", ""),
|
|
130
|
+
comment_generation_prompt=prompts.get("comment_generation", {}).get("system", ""),
|
|
131
|
+
subtask_suggestion_prompt=prompts.get("subtask_suggestion", {}).get("system", ""),
|
|
132
|
+
smart_labeling_prompt=prompts.get("smart_labeling", {}).get("system", ""),
|
|
133
|
+
# Limits
|
|
134
|
+
max_description_length=limits.get("max_description_length", 5000),
|
|
135
|
+
max_subtasks=limits.get("max_subtasks", 10),
|
|
136
|
+
max_comments_to_analyze=limits.get("max_comments_to_analyze", 20),
|
|
137
|
+
max_linked_issues=limits.get("max_linked_issues", 15),
|
|
138
|
+
# AI Parameters
|
|
139
|
+
temperature=limits.get("temperature", agent_meta.get("temperature", 0.7)),
|
|
140
|
+
max_tokens=limits.get("max_tokens", agent_meta.get("max_tokens", 2000)),
|
|
141
|
+
# Features (Active)
|
|
142
|
+
enable_requirement_extraction=features.get("enable_requirement_extraction", True),
|
|
143
|
+
enable_subtasks=features.get("enable_subtasks", True),
|
|
144
|
+
enable_risk_analysis=features.get("enable_risk_analysis", True),
|
|
145
|
+
enable_dependency_detection=features.get("enable_dependency_detection", True),
|
|
146
|
+
enable_acceptance_criteria=features.get("enable_acceptance_criteria", True),
|
|
147
|
+
enable_debug_output=features.get("enable_debug_output", False),
|
|
148
|
+
# Note: Removed unused flags (enable_gherkin_tests, enable_strict_labeling, enable_token_saving)
|
|
149
|
+
# These will be added back when functionality is implemented
|
|
150
|
+
# Formatting
|
|
151
|
+
template=formatting.get("template", ""),
|
|
152
|
+
# Raw for custom access
|
|
153
|
+
raw=data
|
|
154
|
+
)
|