2 Commits

Author SHA1 Message Date
c147d8be78 release: version 0.9.11 🚀
All checks were successful
Upload Python Package / Create Release (push) Successful in 17s
Upload Python Package / deploy (push) Successful in 34s
2026-04-11 20:09:34 +02:00
9ffaa18efe fix: project association improvements, refs NOISSUE 2026-04-11 20:09:31 +02:00
4 changed files with 45 additions and 3 deletions

View File

@@ -5,10 +5,21 @@ Changelog
(unreleased)
------------
Fix
~~~
- Project association improvements, refs NOISSUE. [Simon Diesenreiter]
0.9.10 (2026-04-11)
-------------------
Fix
~~~
- More git integration fixes, refs NOISSUE. [Simon Diesenreiter]
Other
~~~~~
0.9.9 (2026-04-11)
------------------

View File

@@ -1 +1 @@
0.9.10
0.9.11

View File

@@ -133,6 +133,7 @@ class AgentOrchestrator:
features=self.features,
tech_stack=self.tech_stack,
actor_name=self.prompt_actor,
source=self.prompt_actor,
related_issue={'number': self.related_issue_number} if self.related_issue_number is not None else None,
source_context=self.prompt_source_context,
routing=self.prompt_routing,

View File

@@ -31,6 +31,11 @@ class RequestInterpreter:
PLACEHOLDER_PROJECT_NAME_WORDS = {
'generated project', 'new project', 'project', 'temporary name', 'temp name', 'placeholder', 'untitled project',
}
ROUTING_STOPWORDS = REPO_NOISE_WORDS | GENERIC_PROJECT_NAME_WORDS | {
'about', 'after', 'again', 'appropriate', 'before', 'best', 'details', 'follow', 'following', 'implement',
'integration', 'instance', 'instances', 'later', 'make', 'now', 'primary', 'primarily', 'probably',
'remember', 'specific', 'suite', 'tearing', 'testing', 'through', 'used', 'using', 'workflow', 'workflows',
}
def __init__(self, ollama_url: str | None = None, model: str | None = None):
self.ollama_url = (ollama_url or settings.ollama_url).rstrip('/')
@@ -468,6 +473,7 @@ class RequestInterpreter:
projects = context.get('projects', [])
last_project_id = recent_history[0].get('project_id') if recent_history else None
last_issue = ((recent_history[0].get('related_issue') or {}).get('number') if recent_history else None)
last_project = next((project for project in projects if project.get('project_id') == last_project_id), None) if last_project_id else None
matched_project = None
for project in projects:
@@ -481,8 +487,24 @@ class RequestInterpreter:
break
if matched_project is None and not explicit_new:
follow_up_tokens = ['also', 'continue', 'for this project', 'for that project', 'work on this', 'work on that', 'fix that', 'add this']
if any(token in lowered for token in follow_up_tokens) and last_project_id:
matched_project = next((project for project in projects if project.get('project_id') == last_project_id), None)
leading_follow_up = lowered.startswith(('also', 'now', 'continue', 'remember', 'then'))
recent_overlap = 0
if last_project is not None:
recent_prompt_text = recent_history[0].get('prompt_text') or ''
project_reference_text = ' '.join(
part for part in [
last_project.get('name') or '',
last_project.get('description') or '',
((last_project.get('repository') or {}).get('name') or ''),
]
if part
)
recent_overlap = len(
self._routing_tokens(prompt_text)
& (self._routing_tokens(recent_prompt_text) | self._routing_tokens(project_reference_text))
)
if last_project_id and (leading_follow_up or any(token in lowered for token in follow_up_tokens) or recent_overlap >= 2):
matched_project = last_project
issue_number = referenced_issue
if issue_number is None and any(token in lowered for token in ['that issue', 'this issue', 'the issue']) and last_issue is not None:
issue_number = last_issue
@@ -497,6 +519,14 @@ class RequestInterpreter:
'reasoning_summary': 'Heuristic routing from chat history and project names.',
}
def _routing_tokens(self, text: str) -> set[str]:
"""Extract meaningful tokens for heuristic continuation matching."""
cleaned = re.sub(r'[^a-z0-9]+', ' ', (text or '').lower())
return {
token for token in cleaned.split()
if len(token) >= 4 and token not in self.ROUTING_STOPWORDS
}
def _extract_issue_number(self, prompt_text: str) -> int | None:
match = re.search(r'(?:#|issue\s+)(\d+)', prompt_text, flags=re.IGNORECASE)
return int(match.group(1)) if match else None