codee-agent 0.6.7__tar.gz → 0.6.9__tar.gz
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.
- {codee_agent-0.6.7 → codee_agent-0.6.9}/PKG-INFO +1 -1
- {codee_agent-0.6.7 → codee_agent-0.6.9}/pyproject.toml +1 -1
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/admin.py +30 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/admin_service.py +10 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/executor.py +21 -4
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/test_admin_service.py +15 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/test_executor.py +62 -3
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_github_copilot/provider.py +4 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_github_copilot/test.py +16 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_main_context/context.py +8 -1
- {codee_agent-0.6.7 → codee_agent-0.6.9}/LICENSE +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/README.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/.gitignore +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/__init__.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/admin_api.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/admin_cli.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/agent_cli.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/coding_agents.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/init_cli.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/__init__.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/claude_key_rotation.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/cron_describe.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/mcp_config.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/runs_db.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/test_claude_key_rotation.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/test_mcp_config.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/test_runs_db.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/test_trigger_cron_skills.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/test_trigger_issue_skills.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/trigger_aws_sqs_skills.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/trigger_cron_skills.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/trigger_email_skills.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/lib/trigger_issue_skills.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/mail_server.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/setup_wizard.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/start_cli.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/tasks_providers.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/AGENTS.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/CLAUDE.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/aws-sqs-alarm-response/SKILL.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/cron-research-5xx-errors/SKILL.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/story-code-reviewer/SKILL.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/story-developer/SKILL.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/story-planner/SKILL.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/story-planner/assets/readme-template.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/story-qa/SKILL.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/story-security-reviewer/SKILL.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/task-code-reviewer/SKILL.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/task-developer/SKILL.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/task-qa/SKILL.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/task-security-reviewer/SKILL.md +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/test_admin_api.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/test_admin_cli.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/test_agent_cli.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/test_coding_agents.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/test_init_cli.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/test_memory_index.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/test_setup_wizard.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/test_start_cli.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/workflow_graph.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_admin/__init__.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_admin/codee_admin.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_abstract/__init__.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_abstract/provider.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_claude_code/__init__.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_claude_code/account.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_claude_code/credentials.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_claude_code/oauth.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_claude_code/provider.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_claude_code/test.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_claude_code/usage.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_codex/__init__.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_codex/provider.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_codex/test.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_agent_github_copilot/__init__.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_database/__init__.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_database/claude_code_accounts.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_database/database.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_database/oauth_tokens.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_main_context/__init__.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_main_context/logging.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_main_context/test_context.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_main_context/test_logging.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_tasks_abstract/__init__.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_tasks_abstract/provider.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_tasks_azure_devops/__init__.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_tasks_azure_devops/oauth.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_tasks_azure_devops/provider.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_tasks_azure_devops/test.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_tasks_jira/__init__.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_tasks_jira/provider.py +0 -0
- {codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee_tasks_jira/test.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codee-agent
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.9
|
|
4
4
|
Summary: A virtual co-worker that picks up Jira and Azure DevOps tasks and solves them with coding agents.
|
|
5
5
|
Keywords: ai,agent,jira,azure-devops,claude-code,github-copilot,codex,automation
|
|
6
6
|
Author: Denis Kibalko
|
|
@@ -38,6 +38,7 @@ USAGE_POLL_INTERVAL = 60
|
|
|
38
38
|
# installed or uninstalled under a running Codee, and the answer shapes the
|
|
39
39
|
# page rather than anything the user can change on it.
|
|
40
40
|
CLAUDE_CODE_AVAILABLE = SERVICE.claude_code_available()
|
|
41
|
+
GITHUB_COPILOT_AVAILABLE = SERVICE.github_copilot_available()
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
def _skill_summary(skill: dict[str, str]) -> SkillSummary:
|
|
@@ -361,6 +362,7 @@ class AdminState(rx.State):
|
|
|
361
362
|
|
|
362
363
|
tasks_provider: str = "jira"
|
|
363
364
|
coding_agent: str = "claude_code"
|
|
365
|
+
github_copilot_prompt_prefix: str = ""
|
|
364
366
|
max_parallel_agents: str = "3"
|
|
365
367
|
agent_test_open: bool = False
|
|
366
368
|
agent_test_input: str = ""
|
|
@@ -973,6 +975,7 @@ class AdminState(rx.State):
|
|
|
973
975
|
settings = SERVICE.load_settings()
|
|
974
976
|
self.tasks_provider = settings.tasks_provider.value
|
|
975
977
|
self.coding_agent = settings.coding_agent.value
|
|
978
|
+
self.github_copilot_prompt_prefix = settings.github_copilot_prompt_prefix
|
|
976
979
|
self.max_parallel_agents = str(settings.max_parallel_agents)
|
|
977
980
|
self.claude_code_rotate_keys = settings.claude_code_rotate_keys
|
|
978
981
|
self._cancel_claude_code_sign_in()
|
|
@@ -1207,6 +1210,9 @@ class AdminState(rx.State):
|
|
|
1207
1210
|
def set_coding_agent(self, value: str) -> None:
|
|
1208
1211
|
self.coding_agent = value
|
|
1209
1212
|
|
|
1213
|
+
def set_github_copilot_prompt_prefix(self, value: str) -> None:
|
|
1214
|
+
self.github_copilot_prompt_prefix = value
|
|
1215
|
+
|
|
1210
1216
|
def set_max_parallel_agents(self, value: str) -> None:
|
|
1211
1217
|
self.max_parallel_agents = value
|
|
1212
1218
|
|
|
@@ -1549,6 +1555,7 @@ class AdminState(rx.State):
|
|
|
1549
1555
|
work_item_queries,
|
|
1550
1556
|
self._task_filter(),
|
|
1551
1557
|
self.claude_code_rotate_keys,
|
|
1558
|
+
self.github_copilot_prompt_prefix,
|
|
1552
1559
|
)
|
|
1553
1560
|
# Saving is what picks the first account when rotation has just been
|
|
1554
1561
|
# switched on, so the badge has to be redrawn from what that decided.
|
|
@@ -3363,6 +3370,28 @@ def claude_code_setting() -> rx.Component:
|
|
|
3363
3370
|
padding="1.25rem", background=SURFACE, border=BORDER, width="100%")
|
|
3364
3371
|
|
|
3365
3372
|
|
|
3373
|
+
def github_copilot_setting() -> rx.Component:
|
|
3374
|
+
"""Settings used only by GitHub Copilot CLI runs."""
|
|
3375
|
+
return rx.box(
|
|
3376
|
+
rx.heading("GitHub Copilot", size="4", margin_bottom="1rem"),
|
|
3377
|
+
field(
|
|
3378
|
+
"Prompt prefix",
|
|
3379
|
+
rx.text_area(
|
|
3380
|
+
value=AdminState.github_copilot_prompt_prefix,
|
|
3381
|
+
on_change=AdminState.set_github_copilot_prompt_prefix,
|
|
3382
|
+
placeholder="Instructions added before every Copilot prompt",
|
|
3383
|
+
width="100%",
|
|
3384
|
+
min_height="7rem",
|
|
3385
|
+
),
|
|
3386
|
+
rx.text(
|
|
3387
|
+
"Added to the beginning of every prompt sent to GitHub Copilot.",
|
|
3388
|
+
color=MUTED,
|
|
3389
|
+
font_size="0.82rem",
|
|
3390
|
+
),
|
|
3391
|
+
),
|
|
3392
|
+
padding="1.25rem", background=SURFACE, border=BORDER, width="100%")
|
|
3393
|
+
|
|
3394
|
+
|
|
3366
3395
|
def conversation_message(message: ConversationMessage) -> rx.Component:
|
|
3367
3396
|
is_user = message.role == "user"
|
|
3368
3397
|
return rx.box(
|
|
@@ -3540,6 +3569,7 @@ def settings_page() -> rx.Component:
|
|
|
3540
3569
|
# which agents a machine has is not state: there is no event that could
|
|
3541
3570
|
# ever flip it, and nothing on the page should be able to.
|
|
3542
3571
|
claude_code_setting() if CLAUDE_CODE_AVAILABLE else rx.fragment(),
|
|
3572
|
+
github_copilot_setting() if GITHUB_COPILOT_AVAILABLE else rx.fragment(),
|
|
3543
3573
|
rx.box(
|
|
3544
3574
|
rx.heading("Tasks provider", size="4", margin_bottom="1rem"),
|
|
3545
3575
|
field("Provider", rx.select(["jira", "azure_devops"], value=AdminState.tasks_provider,
|
|
@@ -26,6 +26,7 @@ from codee_agent_claude_code.provider import ClaudeCodeAgent
|
|
|
26
26
|
from codee_agent_claude_code.usage import (
|
|
27
27
|
SESSION_WINDOW, WEEKLY_WINDOW, UsageRateLimited, UsageUnavailable,
|
|
28
28
|
fetch_usage)
|
|
29
|
+
from codee_agent_github_copilot.provider import GitHubCopilotAgent
|
|
29
30
|
from codee_tasks_abstract.provider import (
|
|
30
31
|
AbstractTasksProvider, TasksProviderError)
|
|
31
32
|
from codee.coding_agents import (
|
|
@@ -2109,6 +2110,7 @@ class AdminService:
|
|
|
2109
2110
|
work_item_queries: dict[str, str] | None = None,
|
|
2110
2111
|
task_filter: str = "",
|
|
2111
2112
|
claude_code_rotate_keys: bool = False,
|
|
2113
|
+
github_copilot_prompt_prefix: str | None = None,
|
|
2112
2114
|
) -> None:
|
|
2113
2115
|
current = self.context.settings
|
|
2114
2116
|
all_credentials = dict(current.credentials)
|
|
@@ -2132,6 +2134,10 @@ class AdminService:
|
|
|
2132
2134
|
self.context.settings = Settings(
|
|
2133
2135
|
tasks_provider=TasksProvider(tasks_provider),
|
|
2134
2136
|
coding_agent=CodingAgent(coding_agent),
|
|
2137
|
+
github_copilot_prompt_prefix=(
|
|
2138
|
+
current.github_copilot_prompt_prefix
|
|
2139
|
+
if github_copilot_prompt_prefix is None
|
|
2140
|
+
else github_copilot_prompt_prefix.strip()),
|
|
2135
2141
|
credentials=all_credentials,
|
|
2136
2142
|
work_item_types=all_work_items,
|
|
2137
2143
|
work_item_queries=all_work_item_queries,
|
|
@@ -2152,6 +2158,10 @@ class AdminService:
|
|
|
2152
2158
|
"""
|
|
2153
2159
|
return ClaudeCodeAgent.is_installed()
|
|
2154
2160
|
|
|
2161
|
+
def github_copilot_available(self) -> bool:
|
|
2162
|
+
"""Whether this machine has the GitHub Copilot CLI installed."""
|
|
2163
|
+
return GitHubCopilotAgent.is_installed()
|
|
2164
|
+
|
|
2155
2165
|
def claude_code_accounts(self) -> list[ConnectedAccount]:
|
|
2156
2166
|
"""The connected accounts, in rotation order, for the settings page."""
|
|
2157
2167
|
try:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import os
|
|
2
3
|
import subprocess
|
|
3
4
|
import threading
|
|
4
5
|
import time
|
|
@@ -9,11 +10,12 @@ from datetime import datetime, timezone
|
|
|
9
10
|
from codee_agent_abstract.provider import AbstractCodingAgent
|
|
10
11
|
from codee_agent_claude_code.provider import ClaudeCodeAgent
|
|
11
12
|
from codee_agent_codex.provider import CodexAgent
|
|
12
|
-
from codee_agent_github_copilot.provider import
|
|
13
|
+
from codee_agent_github_copilot.provider import (
|
|
14
|
+
COPILOT_DEBUG_ENV_VAR, GitHubCopilotAgent)
|
|
13
15
|
from codee_main_context.context import (
|
|
14
16
|
CodeeMainContext, CodingAgent, Settings, codee_issue_types, data_dir,
|
|
15
17
|
load_settings, project_root)
|
|
16
|
-
from codee_main_context.logging import configure_logging, get_logger
|
|
18
|
+
from codee_main_context.logging import DEBUG_ENV_VAR, configure_logging, get_logger
|
|
17
19
|
from codee_tasks_abstract.provider import AbstractTasksProvider
|
|
18
20
|
|
|
19
21
|
from codee.coding_agents import resolve_agent_code
|
|
@@ -70,6 +72,13 @@ def _max_parallel_agents() -> int:
|
|
|
70
72
|
return max(1, context.settings.max_parallel_agents)
|
|
71
73
|
|
|
72
74
|
|
|
75
|
+
def _log_debug_environment() -> None:
|
|
76
|
+
if os.environ.get(COPILOT_DEBUG_ENV_VAR, "").strip().lower() == "true":
|
|
77
|
+
log.info("COPILOT_DEBUG=true (Copilot CLI debug logs enabled)")
|
|
78
|
+
if os.environ.get(DEBUG_ENV_VAR, "").strip() == "1":
|
|
79
|
+
log.info("CODEE_DEBUG=1 (Codee debug logging enabled)")
|
|
80
|
+
|
|
81
|
+
|
|
73
82
|
def _load_sessions() -> dict[str, str]:
|
|
74
83
|
"""Load task_id -> session_id mapping from disk."""
|
|
75
84
|
if SESSIONS_FILE.exists():
|
|
@@ -171,7 +180,13 @@ def _refresh_config() -> None:
|
|
|
171
180
|
else:
|
|
172
181
|
log.info("Reloaded tasks provider: %s", tasks_provider.describe())
|
|
173
182
|
|
|
174
|
-
|
|
183
|
+
coding_agent_changed = settings.coding_agent != previous.coding_agent
|
|
184
|
+
copilot_settings_changed = (
|
|
185
|
+
settings.coding_agent == CodingAgent.GITHUB_COPILOT
|
|
186
|
+
and settings.github_copilot_prompt_prefix
|
|
187
|
+
!= previous.github_copilot_prompt_prefix
|
|
188
|
+
)
|
|
189
|
+
if coding_agent_changed or copilot_settings_changed:
|
|
175
190
|
try:
|
|
176
191
|
coding_agent = _build_coding_agent(settings)
|
|
177
192
|
except Exception as exc:
|
|
@@ -276,7 +291,8 @@ def _run_agent(user_message: str, session_id: str, model: str = "",
|
|
|
276
291
|
"""
|
|
277
292
|
if agent_session_id == session_id:
|
|
278
293
|
return
|
|
279
|
-
log.debug("job %s runs under agent session %s",
|
|
294
|
+
log.debug("job %s runs under agent session %s",
|
|
295
|
+
job_id, agent_session_id)
|
|
280
296
|
runs_db.note_agent_session(session_id, agent_session_id)
|
|
281
297
|
runs_db.set_job_session(job_id, agent_session_id, main_context=context)
|
|
282
298
|
|
|
@@ -460,6 +476,7 @@ def main() -> None:
|
|
|
460
476
|
# Entry point: install the handler before anything logs. Level comes from
|
|
461
477
|
# CODEE_DEBUG, which `codee-start --debug` exports for this subprocess.
|
|
462
478
|
configure_logging()
|
|
479
|
+
_log_debug_environment()
|
|
463
480
|
|
|
464
481
|
if not tasks_provider.is_configured():
|
|
465
482
|
log.warning("tasks provider is not configured; task polling stays "
|
|
@@ -258,6 +258,21 @@ class AdminServiceWorkItemsTest(unittest.TestCase):
|
|
|
258
258
|
|
|
259
259
|
self.assertEqual(load_settings(directory).task_filters["jira"], "")
|
|
260
260
|
|
|
261
|
+
def test_saving_preserves_the_github_copilot_prompt_prefix(self) -> None:
|
|
262
|
+
with tempfile.TemporaryDirectory() as temporary_directory:
|
|
263
|
+
directory = Path(temporary_directory)
|
|
264
|
+
service = self._service(directory)
|
|
265
|
+
|
|
266
|
+
service.save_settings(
|
|
267
|
+
"jira", "github_copilot", 3, {},
|
|
268
|
+
github_copilot_prompt_prefix="Follow repository policy.",
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
self.assertEqual(
|
|
272
|
+
load_settings(directory).github_copilot_prompt_prefix,
|
|
273
|
+
"Follow repository policy.",
|
|
274
|
+
)
|
|
275
|
+
|
|
261
276
|
def test_saving_keeps_the_other_provider_s_work_item_queries(self) -> None:
|
|
262
277
|
# A JQL condition means nothing to Azure DevOps, so each provider keeps
|
|
263
278
|
# its own and switching between them loses neither.
|
|
@@ -19,6 +19,28 @@ from codee.lib import runs_db
|
|
|
19
19
|
from codee.lib.trigger_issue_skills import IssueTriggeredSkill
|
|
20
20
|
|
|
21
21
|
|
|
22
|
+
class DebugEnvironmentLoggingTest(unittest.TestCase):
|
|
23
|
+
def test_enabled_debug_flags_are_logged_at_startup(self) -> None:
|
|
24
|
+
with patch.dict(os.environ, {
|
|
25
|
+
"COPILOT_DEBUG": "TRUE",
|
|
26
|
+
"CODEE_DEBUG": "1",
|
|
27
|
+
}, clear=True), patch.object(executor.log, "info") as info:
|
|
28
|
+
executor._log_debug_environment()
|
|
29
|
+
|
|
30
|
+
info.assert_any_call(
|
|
31
|
+
"COPILOT_DEBUG=true (Copilot CLI debug logs enabled)")
|
|
32
|
+
info.assert_any_call("CODEE_DEBUG=1 (Codee debug logging enabled)")
|
|
33
|
+
|
|
34
|
+
def test_disabled_debug_flags_are_not_logged(self) -> None:
|
|
35
|
+
with patch.dict(os.environ, {
|
|
36
|
+
"COPILOT_DEBUG": "false",
|
|
37
|
+
"CODEE_DEBUG": "true",
|
|
38
|
+
}, clear=True), patch.object(executor.log, "info") as info:
|
|
39
|
+
executor._log_debug_environment()
|
|
40
|
+
|
|
41
|
+
info.assert_not_called()
|
|
42
|
+
|
|
43
|
+
|
|
22
44
|
class RefreshConfigTest(unittest.TestCase):
|
|
23
45
|
"""The executor re-reads settings.json each poll, so edits need no restart."""
|
|
24
46
|
|
|
@@ -68,7 +90,8 @@ class RefreshConfigTest(unittest.TestCase):
|
|
|
68
90
|
|
|
69
91
|
executor._refresh_config()
|
|
70
92
|
|
|
71
|
-
self.assertIsInstance(executor.tasks_provider,
|
|
93
|
+
self.assertIsInstance(executor.tasks_provider,
|
|
94
|
+
AzureDevOpsTasksProvider)
|
|
72
95
|
self.assertEqual(executor.context.settings.tasks_provider,
|
|
73
96
|
TasksProvider.AZURE_DEVOPS)
|
|
74
97
|
|
|
@@ -144,6 +167,40 @@ class RefreshConfigTest(unittest.TestCase):
|
|
|
144
167
|
self.assertEqual(executor.context.settings.coding_agent,
|
|
145
168
|
CodingAgent.GITHUB_COPILOT)
|
|
146
169
|
|
|
170
|
+
def test_changing_copilot_prompt_prefix_rebuilds_the_default_agent(self) -> None:
|
|
171
|
+
self._save(coding_agent=CodingAgent.GITHUB_COPILOT)
|
|
172
|
+
executor._refresh_config()
|
|
173
|
+
original = executor.coding_agent
|
|
174
|
+
|
|
175
|
+
self._save(
|
|
176
|
+
coding_agent=CodingAgent.GITHUB_COPILOT,
|
|
177
|
+
github_copilot_prompt_prefix="Follow repository policy.",
|
|
178
|
+
)
|
|
179
|
+
executor._refresh_config()
|
|
180
|
+
|
|
181
|
+
self.assertIsNot(executor.coding_agent, original)
|
|
182
|
+
completed = Mock(
|
|
183
|
+
returncode=0,
|
|
184
|
+
stdout=(
|
|
185
|
+
'{"type":"assistant.message","data":{"content":"ok"}}\n'
|
|
186
|
+
'{"type":"result","exitCode":0}\n'
|
|
187
|
+
),
|
|
188
|
+
stderr="",
|
|
189
|
+
)
|
|
190
|
+
issue_prompt = (
|
|
191
|
+
"Read .claude/skills/story-qa/SKILL.md and follow its "
|
|
192
|
+
"instructions exactly. STORY_ID = 92146"
|
|
193
|
+
)
|
|
194
|
+
with patch("codee_agent_github_copilot.provider.subprocess.run",
|
|
195
|
+
return_value=completed) as run:
|
|
196
|
+
executor._agent_for_skill("").run(issue_prompt, "session-1")
|
|
197
|
+
|
|
198
|
+
command = run.call_args.args[0]
|
|
199
|
+
self.assertEqual(
|
|
200
|
+
command[command.index("-p") + 1],
|
|
201
|
+
f"Follow repository policy.\n\n{issue_prompt}",
|
|
202
|
+
)
|
|
203
|
+
|
|
147
204
|
def test_broken_coding_agent_settings_keep_polling_with_the_old_one(self) -> None:
|
|
148
205
|
self._save(coding_agent=CodingAgent.CLAUDE_CODE)
|
|
149
206
|
executor._refresh_config()
|
|
@@ -446,10 +503,12 @@ class ParentWorkItemSkipTest(unittest.TestCase):
|
|
|
446
503
|
self.provider.is_configured.return_value = True
|
|
447
504
|
self.skills = [
|
|
448
505
|
IssueTriggeredSkill(name="Task developer", slug="task-developer",
|
|
449
|
-
path=Path(
|
|
506
|
+
path=Path(
|
|
507
|
+
"/repo/.claude/skills/task/SKILL.md"),
|
|
450
508
|
statuses=("Ready",), issue_type="task"),
|
|
451
509
|
IssueTriggeredSkill(name="Story developer", slug="story-developer",
|
|
452
|
-
path=Path(
|
|
510
|
+
path=Path(
|
|
511
|
+
"/repo/.claude/skills/story/SKILL.md"),
|
|
453
512
|
statuses=("Ready",), issue_type="story"),
|
|
454
513
|
]
|
|
455
514
|
for name in ("trigger_cron_skills", "trigger_aws_sqs_skills",
|
|
@@ -67,6 +67,7 @@ class GitHubCopilotAgent(AbstractCodingAgent):
|
|
|
67
67
|
|
|
68
68
|
def __init__(self, settings: Settings, cwd: Path):
|
|
69
69
|
super().__init__(settings, cwd)
|
|
70
|
+
self._settings = settings
|
|
70
71
|
|
|
71
72
|
@classmethod
|
|
72
73
|
def best_model(cls) -> str:
|
|
@@ -104,6 +105,9 @@ class GitHubCopilotAgent(AbstractCodingAgent):
|
|
|
104
105
|
# answer is known before the run starts.
|
|
105
106
|
if on_session_id:
|
|
106
107
|
on_session_id(session_id)
|
|
108
|
+
prefix = self._settings.github_copilot_prompt_prefix.strip()
|
|
109
|
+
if prefix:
|
|
110
|
+
user_message = f"{prefix}\n\n{user_message}"
|
|
107
111
|
cmd = [
|
|
108
112
|
self.CLI_COMMAND,
|
|
109
113
|
"-p", user_message,
|
|
@@ -122,6 +122,22 @@ class CopilotRunTest(unittest.TestCase):
|
|
|
122
122
|
self.assertEqual(self.captured.call_args.kwargs["encoding"], "utf-8")
|
|
123
123
|
self.assertEqual(self.captured.call_args.kwargs["errors"], "replace")
|
|
124
124
|
|
|
125
|
+
def test_prepends_the_configured_prompt_prefix(self) -> None:
|
|
126
|
+
self.agent = GitHubCopilotAgent(
|
|
127
|
+
Settings(github_copilot_prompt_prefix="Follow repository policy."),
|
|
128
|
+
Path("/repo"),
|
|
129
|
+
)
|
|
130
|
+
stdout = _stream(_event("assistant.message", {"content": "ok"}),
|
|
131
|
+
_event("result", exitCode=0))
|
|
132
|
+
|
|
133
|
+
self._run(_completed(stdout))
|
|
134
|
+
|
|
135
|
+
cmd = self.captured.call_args.args[0]
|
|
136
|
+
self.assertEqual(
|
|
137
|
+
cmd[cmd.index("-p") + 1],
|
|
138
|
+
"Follow repository policy.\n\n/do-it CORE-1",
|
|
139
|
+
)
|
|
140
|
+
|
|
125
141
|
def test_continuing_reuses_the_same_session_id(self) -> None:
|
|
126
142
|
stdout = _stream(_event("assistant.message", {"content": "ok"}),
|
|
127
143
|
_event("result", exitCode=0))
|
|
@@ -142,6 +142,9 @@ class Settings:
|
|
|
142
142
|
tasks_provider: TasksProvider = TasksProvider.JIRA
|
|
143
143
|
# Which coding agent the executor drives to work on tasks.
|
|
144
144
|
coding_agent: CodingAgent = CodingAgent.CLAUDE_CODE
|
|
145
|
+
# Text prepended to every prompt sent to GitHub Copilot. Other coding
|
|
146
|
+
# agents do not read this setting.
|
|
147
|
+
github_copilot_prompt_prefix: str = ""
|
|
145
148
|
# Per-provider credentials, keyed by provider value -> {field key: value}.
|
|
146
149
|
# Values for all providers are kept so switching provider preserves them.
|
|
147
150
|
credentials: dict[str, dict[str, str]] = field(default_factory=dict)
|
|
@@ -156,7 +159,8 @@ class Settings:
|
|
|
156
159
|
# mandatory, settings written before one work item could name several types
|
|
157
160
|
# hold a bare string where there is now a list, and a work item selected by
|
|
158
161
|
# a query ignores its types entirely.
|
|
159
|
-
work_item_types: dict[str, dict[str, list[str]]
|
|
162
|
+
work_item_types: dict[str, dict[str, list[str]]
|
|
163
|
+
] = field(default_factory=dict)
|
|
160
164
|
# The advanced answer to the same question: a condition in the provider's
|
|
161
165
|
# own query language that picks one Codee work item out of the backend,
|
|
162
166
|
# keyed by provider value -> {codee work item: condition}. Set for a work
|
|
@@ -202,6 +206,8 @@ def load_settings(data_dir: Path) -> Settings:
|
|
|
202
206
|
tasks_provider=TasksProvider(data["tasks_provider"]),
|
|
203
207
|
coding_agent=CodingAgent(
|
|
204
208
|
data.get("coding_agent", CodingAgent.CLAUDE_CODE.value)),
|
|
209
|
+
github_copilot_prompt_prefix=str(
|
|
210
|
+
data.get("github_copilot_prompt_prefix", "")),
|
|
205
211
|
credentials=data.get("credentials", {}),
|
|
206
212
|
work_item_types=data.get("work_item_types", {}),
|
|
207
213
|
work_item_queries=data.get("work_item_queries", {}),
|
|
@@ -225,6 +231,7 @@ def save_settings(data_dir: Path, settings: Settings) -> None:
|
|
|
225
231
|
payload = json.dumps({
|
|
226
232
|
"tasks_provider": settings.tasks_provider.value,
|
|
227
233
|
"coding_agent": settings.coding_agent.value,
|
|
234
|
+
"github_copilot_prompt_prefix": settings.github_copilot_prompt_prefix,
|
|
228
235
|
"credentials": settings.credentials,
|
|
229
236
|
"work_item_types": settings.work_item_types,
|
|
230
237
|
"work_item_queries": settings.work_item_queries,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/aws-sqs-alarm-response/SKILL.md
RENAMED
|
File without changes
|
{codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/cron-research-5xx-errors/SKILL.md
RENAMED
|
File without changes
|
{codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/story-code-reviewer/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/story-security-reviewer/SKILL.md
RENAMED
|
File without changes
|
{codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/task-code-reviewer/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codee_agent-0.6.7 → codee_agent-0.6.9}/src/codee/templates/skills/task-security-reviewer/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|