devops-bot-sdk 1.4.78__tar.gz → 1.4.81__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.
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/pyproject.toml +1 -1
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/client.py +1 -1
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/ipc/handlers.py +46 -8
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/README.md +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/devops_bot_sdk.egg-info/SOURCES.txt +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/devops_bot_sdk.egg-info/requires.txt +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/config.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/git_ops.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/graphify.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/local_exec.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/run_auto.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/test.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/sdk/updater.py +0 -0
- {devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/setup.cfg +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "devops-bot-sdk"
|
|
7
|
-
version = "1.4.
|
|
7
|
+
version = "1.4.81"
|
|
8
8
|
description = "DevOps Bot Desktop SDK — thin client for the AgentOS Electron desktop app"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "LicenseRef-Proprietary"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
|
|
2
2
|
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.81
|
|
4
4
|
|
|
5
5
|
Public surface:
|
|
6
6
|
BackendClient.from_config() — create client from ~/.agentos/config.toml
|
|
@@ -30,7 +30,7 @@ Rules:
|
|
|
30
30
|
- All data egress through submit_webhook only
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
|
-
__version__ = "1.4.
|
|
33
|
+
__version__ = "1.4.81"
|
|
34
34
|
__author__ = "AgentOS"
|
|
35
35
|
|
|
36
36
|
from sdk.client import BackendClient
|
|
@@ -531,7 +531,7 @@ _PRD_FORMAT = (
|
|
|
531
531
|
|
|
532
532
|
|
|
533
533
|
def _build_epic_prompt(jira_key: str, summary: str, description: str | None,
|
|
534
|
-
human_instructions: str | None) -> str:
|
|
534
|
+
human_instructions: str | None, story_count: int | None = None) -> str:
|
|
535
535
|
"""Read-only prompt that turns an Epic into a decomposition JSON."""
|
|
536
536
|
parts: list[str] = [
|
|
537
537
|
"You are decomposing a JIRA EPIC into implementable user stories. This is "
|
|
@@ -578,9 +578,12 @@ def _build_epic_prompt(jira_key: str, summary: str, description: str | None,
|
|
|
578
578
|
"}\n\n"
|
|
579
579
|
"Do NOT produce humanInstructions for the stories — created stories are clean "
|
|
580
580
|
"user-story artifacts; implementation instructions are added later.\n"
|
|
581
|
-
"
|
|
582
|
-
|
|
583
|
-
|
|
581
|
+
+ (f"Generate EXACTLY {story_count} user stor{'y' if story_count == 1 else 'ies'} — "
|
|
582
|
+
"the epic explicitly asks for this many; do not produce more or fewer.\n"
|
|
583
|
+
if story_count else
|
|
584
|
+
"Create as many stories as the epic genuinely needs (do not pad or truncate "
|
|
585
|
+
"artificially); each story must be independently implementable.\n")
|
|
586
|
+
+ "assigneeEmail is OPTIONAL per story: set it ONLY when the epic explicitly "
|
|
584
587
|
"assigns that specific work to a named person/email (e.g. 'assign the API to "
|
|
585
588
|
"alice@x.com'); otherwise omit it.\n\n"
|
|
586
589
|
"=== EPIC FORMAT (epic_description MUST follow this exactly) ===\n"
|
|
@@ -650,6 +653,37 @@ _STORIES_DIR_HINT = re.compile(
|
|
|
650
653
|
)
|
|
651
654
|
|
|
652
655
|
|
|
656
|
+
# An explicit "build N user stories" count in the description/instructions.
|
|
657
|
+
_STORY_COUNT_WORDS = {
|
|
658
|
+
"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6,
|
|
659
|
+
"seven": 7, "eight": 8, "nine": 9, "ten": 10, "eleven": 11, "twelve": 12,
|
|
660
|
+
}
|
|
661
|
+
_STORY_COUNT_RE = re.compile(
|
|
662
|
+
r"\b(\d{1,2})\s+(?:user\s+)?stor(?:y|ies)\b"
|
|
663
|
+
r"|\b(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve)"
|
|
664
|
+
r"\s+(?:user\s+)?stor(?:y|ies)\b",
|
|
665
|
+
re.I,
|
|
666
|
+
)
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
def _extract_story_count(text: str | None) -> int | None:
|
|
670
|
+
"""A requested number of user stories from the text (e.g. "build 3 user stories",
|
|
671
|
+
"create five stories"), or None. Bounded to a sane max."""
|
|
672
|
+
if not text:
|
|
673
|
+
return None
|
|
674
|
+
m = _STORY_COUNT_RE.search(text)
|
|
675
|
+
if not m:
|
|
676
|
+
return None
|
|
677
|
+
if m.group(1):
|
|
678
|
+
try:
|
|
679
|
+
n = int(m.group(1))
|
|
680
|
+
except ValueError:
|
|
681
|
+
return None
|
|
682
|
+
else:
|
|
683
|
+
n = _STORY_COUNT_WORDS.get((m.group(2) or "").lower(), 0)
|
|
684
|
+
return min(n, 50) if n and n >= 1 else None
|
|
685
|
+
|
|
686
|
+
|
|
653
687
|
def _extract_stories_dir(text: str | None) -> str | None:
|
|
654
688
|
"""A directory the instructions ask the user stories to be WRITTEN into, or None.
|
|
655
689
|
|
|
@@ -845,12 +879,16 @@ async def _handle_epic(
|
|
|
845
879
|
).model_dump())
|
|
846
880
|
|
|
847
881
|
# 1. Generate the decomposition, grounded in the codebase where one exists.
|
|
882
|
+
# If the description/instructions ask for a specific number of stories, honor
|
|
883
|
+
# it exactly; otherwise the model decides (bounded by _MAX_EPIC_STORIES).
|
|
884
|
+
story_count = _extract_story_count(description) or _extract_story_count(human)
|
|
885
|
+
limit = story_count or _MAX_EPIC_STORIES
|
|
848
886
|
try:
|
|
849
887
|
await graphify.prepare(project_path)
|
|
850
888
|
except Exception: # noqa: BLE001
|
|
851
889
|
pass
|
|
852
890
|
gen = await _run_generation(
|
|
853
|
-
_build_epic_prompt(jira_key, summary, description, human),
|
|
891
|
+
_build_epic_prompt(jira_key, summary, description, human, story_count=story_count),
|
|
854
892
|
project_path, send=send, thread_id=thread_id,
|
|
855
893
|
label=f"Epic {jira_key}: generating user stories",
|
|
856
894
|
github_token=await client.github_token(),
|
|
@@ -893,7 +931,7 @@ async def _handle_epic(
|
|
|
893
931
|
await send(Envelope(
|
|
894
932
|
type="step_update", thread_id=thread_id,
|
|
895
933
|
data={"jira_task_id": tid, "current_step": f"Epic {jira_key}: marked Done — "
|
|
896
|
-
f"creating {min(len(stories),
|
|
934
|
+
f"creating {min(len(stories), limit)} user Story(ies)"},
|
|
897
935
|
).model_dump())
|
|
898
936
|
|
|
899
937
|
# 3. Create a To Do child Task per story, inheriting the Epic's fields.
|
|
@@ -902,7 +940,7 @@ async def _handle_epic(
|
|
|
902
940
|
# inherited assignee — but ONLY on the CHILD task, never on the parent Epic.
|
|
903
941
|
desc_email = _extract_email(description) or _extract_email(human)
|
|
904
942
|
created: list[str] = []
|
|
905
|
-
for st in stories[:
|
|
943
|
+
for st in stories[:limit]:
|
|
906
944
|
if not isinstance(st, dict) or not (st.get("summary") or "").strip():
|
|
907
945
|
continue
|
|
908
946
|
# Precedence: a per-story email the model extracted → an email in the
|
|
@@ -945,7 +983,7 @@ async def _handle_epic(
|
|
|
945
983
|
d = Path(stories_dir).expanduser()
|
|
946
984
|
d.mkdir(parents=True, exist_ok=True) # create from scratch
|
|
947
985
|
written = 0
|
|
948
|
-
for i, st in enumerate(stories[:
|
|
986
|
+
for i, st in enumerate(stories[:limit], 1):
|
|
949
987
|
if not isinstance(st, dict) or not (st.get("summary") or "").strip():
|
|
950
988
|
continue
|
|
951
989
|
title = str(st.get("summary", "")).strip()
|
|
File without changes
|
|
File without changes
|
{devops_bot_sdk-1.4.78 → devops_bot_sdk-1.4.81}/devops_bot_sdk.egg-info/dependency_links.txt
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
|