kiwi-code 0.0.513__tar.gz → 0.0.514__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.
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/PKG-INFO +1 -1
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/pyproject.toml +1 -1
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/role_mode.py +69 -24
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/term_dashboard.py +9 -6
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_role_mode_injection.py +76 -18
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/uv.lock +1 -1
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/.github/workflows/publish.yml +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/.github/workflows/test.yml +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/.gitignore +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/.python-version +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/Makefile +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/README.md +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/docs/runtime_audit.html +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/docs/social_login_e2e.md +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/scripts/set_edition.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/scripts/ws_auth_check.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/common/__init__.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/common/banner.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/__init__.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/_edition.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/auth.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/autocode.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/checkpoints.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/cli.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/client.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/commands.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/edition.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/human_questions.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/io_threads.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/logger.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/models.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/oauth.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/run_activity.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/runtime_manager.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/server.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/subagents.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_cli/terminal_mode.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/__init__.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/__main__.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/auth.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/checkpoints.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/cli.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/commands.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/constants.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/fs/__init__.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/fs/batch.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/fs/codelens.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/fs/context.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/fs/edits.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/fs/handler.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/fs/paths.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/fs/read.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/fs/search.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/fs/text.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/fs/upload.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/fs/write.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/handlers.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/link.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/main.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/restricted.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/sessions.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/state.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/tui_bridge.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/ui.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_runtime/uploads.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/__init__.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/attention.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/autoupdate.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/inline_file_picker.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/latex_unicode.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/main.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/random_words.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/runtime_agent.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/__init__.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/attach_content.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/command_result.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/detach_files.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/file_browser.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/help.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/id_picker.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/login.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/runtime_cleanup.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/runtime_logs.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/slash_picker.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/term_activity_view.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/term_dashboard_css.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/term_dashboard_helpers.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/term_dashboard_widgets.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/term_question_widgets.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/term_status_line.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/screens/term_subagent_widgets.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/slash_commands.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/status_words.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/term_app.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/terminal_theme.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/ui_settings.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/widgets.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/src/kiwi_tui/worktrees.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/test_hello.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/__init__.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/conftest.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_account_server.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_attention.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_autocode_actions.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_autoupdate.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_batch_fs_tool.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_checkpoints.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_cli_help.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_command_tips.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_copy_path_fs_tool.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_fs_edit_fidelity.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_human_questions.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_imports.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_io_threads.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_login_social.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_math_and_tables.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_oauth.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_read_file_streaming.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_reexec_kiwi.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_reply_selection.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_run_activity.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_run_steering.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_runtime_cleanup_per_account.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_runtime_connection.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_runtime_edit_diffs.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_runtime_fixes.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_runtime_imports_on_windows.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_runtime_log_trimming.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_runtime_social_login.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_search_in_files_fs_tool.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_slash_commands.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_stats_command.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_status_line.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_subagents.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_term_dashboard_ui.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_terminal_mode.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_terminal_theme.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_toasts.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_tokens.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_tui_interactive_runtime.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_tui_palette.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_unified_diff.py +0 -0
- {kiwi_code-0.0.513 → kiwi_code-0.0.514}/tests/test_worktrees.py +0 -0
|
@@ -113,7 +113,20 @@ def mode_skill_line(*, role: str, mode: str) -> str:
|
|
|
113
113
|
|
|
114
114
|
|
|
115
115
|
|
|
116
|
+
SYSTEM_PROMPT_HEADING = "# System Prompt"
|
|
117
|
+
MODE_SKILL_INTRO = "Plus use this exact mode skill(only)."
|
|
118
|
+
|
|
119
|
+
# Wording sent by older versions; still stripped when rendering stored history.
|
|
120
|
+
_LEGACY_MODE_SKILL_INTRO = "Plus extract this exact mode skill(only)."
|
|
121
|
+
|
|
122
|
+
|
|
116
123
|
def _general_role_line(role: str) -> str:
|
|
124
|
+
return (
|
|
125
|
+
f"Your Current Role is : {role}. Use autocode.{role}.general skill and act accordingly."
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _legacy_general_role_line(role: str) -> str:
|
|
117
130
|
return (
|
|
118
131
|
f"Your Current Role is : {role}. Fetch autocode.{role}.general skill and act accordingly."
|
|
119
132
|
)
|
|
@@ -122,14 +135,35 @@ def _general_role_line(role: str) -> str:
|
|
|
122
135
|
_SKILL_LINE_RE = re.compile(r"^autocode\.([a-z\-]+)\.(plan|build|validate) skill$")
|
|
123
136
|
|
|
124
137
|
|
|
125
|
-
def
|
|
126
|
-
"""
|
|
138
|
+
def _injected_lines_end(lines: list[str], start: int) -> int:
|
|
139
|
+
"""Index just past the injected role/mode lines found at `start` (== start if none)."""
|
|
140
|
+
i = start
|
|
141
|
+
current = (lines[i] or "").strip() if i < len(lines) else ""
|
|
142
|
+
for r in CANONICAL_ROLES:
|
|
143
|
+
if current in (_general_role_line(r), _legacy_general_role_line(r)):
|
|
144
|
+
i += 1
|
|
145
|
+
break
|
|
146
|
+
|
|
147
|
+
if i < len(lines) and (lines[i] or "").strip() in (MODE_SKILL_INTRO, _LEGACY_MODE_SKILL_INTRO):
|
|
148
|
+
# Skip the "Plus..." line
|
|
149
|
+
i += 1
|
|
150
|
+
# Skip the skill line only if it matches the expected pattern.
|
|
151
|
+
if i < len(lines) and _SKILL_LINE_RE.match((lines[i] or "").strip()):
|
|
152
|
+
i += 1
|
|
153
|
+
return i
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def strip_injected_prompt(text: str) -> str:
|
|
157
|
+
"""Strip the silent role/mode injection (if present) from a stored user prompt.
|
|
127
158
|
|
|
128
159
|
The backend persists the full user_input we send, which will include the
|
|
129
|
-
injected
|
|
160
|
+
injected lines. When rendering conversation history, we must not show these
|
|
130
161
|
injected lines to the user.
|
|
131
162
|
|
|
132
|
-
|
|
163
|
+
Current format: the user's text, then a "# System Prompt" block at the end.
|
|
164
|
+
Older formats put the injected lines (with or without the heading) first.
|
|
165
|
+
|
|
166
|
+
We only strip when the lines match *exactly* our known injection format,
|
|
133
167
|
to avoid altering legitimate user content.
|
|
134
168
|
"""
|
|
135
169
|
raw = (text or "")
|
|
@@ -140,19 +174,29 @@ def strip_injected_prefix(text: str) -> str:
|
|
|
140
174
|
if not lines:
|
|
141
175
|
return raw
|
|
142
176
|
|
|
177
|
+
# Current format: a trailing "# System Prompt" block that runs to the end.
|
|
178
|
+
for h in range(len(lines) - 1, -1, -1):
|
|
179
|
+
if (lines[h] or "").strip() != SYSTEM_PROMPT_HEADING:
|
|
180
|
+
continue
|
|
181
|
+
end = _injected_lines_end(lines, h + 1)
|
|
182
|
+
if end > h + 1 and all(not (rest or "").strip() for rest in lines[end:]):
|
|
183
|
+
body = lines[:h]
|
|
184
|
+
while body and body[-1] == "":
|
|
185
|
+
body.pop()
|
|
186
|
+
return "\n".join(body)
|
|
187
|
+
break
|
|
188
|
+
|
|
189
|
+
# Older formats: injected lines at the start.
|
|
143
190
|
i = 0
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
# Skip the skill line only if it matches the expected pattern.
|
|
154
|
-
if i < len(lines) and _SKILL_LINE_RE.match((lines[i] or "").strip()):
|
|
155
|
-
i += 1
|
|
191
|
+
has_heading = (lines[0] or "").strip() == SYSTEM_PROMPT_HEADING
|
|
192
|
+
if has_heading:
|
|
193
|
+
i = 1
|
|
194
|
+
body_start = i
|
|
195
|
+
i = _injected_lines_end(lines, i)
|
|
196
|
+
|
|
197
|
+
# A heading with no injected lines after it is the user's own text; keep it.
|
|
198
|
+
if has_heading and i == body_start:
|
|
199
|
+
return raw
|
|
156
200
|
|
|
157
201
|
# Skip blank separator lines
|
|
158
202
|
while i < len(lines) and lines[i] == "":
|
|
@@ -223,7 +267,8 @@ def build_model_user_prompt(
|
|
|
223
267
|
) -> tuple[str, RoleModeState]:
|
|
224
268
|
"""Return (model_user_prompt, new_state).
|
|
225
269
|
|
|
226
|
-
The
|
|
270
|
+
The user's text comes first; any required silent injection follows it as a
|
|
271
|
+
"# System Prompt" block.
|
|
227
272
|
|
|
228
273
|
Injection rules:
|
|
229
274
|
- If first model prompt OR role changed: inject the role+general line.
|
|
@@ -236,16 +281,16 @@ def build_model_user_prompt(
|
|
|
236
281
|
inject_general = is_first or state.role_changed
|
|
237
282
|
inject_mode = is_first or state.role_changed or state.mode_changed
|
|
238
283
|
|
|
239
|
-
|
|
284
|
+
injected: list[str] = []
|
|
240
285
|
if inject_general:
|
|
241
|
-
|
|
242
|
-
f"Your Current Role is : {state.role}. Fetch autocode.{state.role}.general skill and act accordingly.\n"
|
|
243
|
-
)
|
|
286
|
+
injected.append(_general_role_line(state.role))
|
|
244
287
|
if inject_mode:
|
|
245
|
-
|
|
246
|
-
|
|
288
|
+
injected.append(MODE_SKILL_INTRO)
|
|
289
|
+
injected.append(mode_skill_line(role=state.role, mode=state.mode))
|
|
247
290
|
|
|
248
|
-
model_prompt =
|
|
291
|
+
model_prompt = raw_user_prompt or ""
|
|
292
|
+
if injected:
|
|
293
|
+
model_prompt += "\n\n" + "\n".join([SYSTEM_PROMPT_HEADING, *injected])
|
|
249
294
|
|
|
250
295
|
new_state = replace(
|
|
251
296
|
state,
|
|
@@ -28,13 +28,14 @@ from kiwi_tui.random_words import random_verb
|
|
|
28
28
|
from kiwi_tui.role_mode import (
|
|
29
29
|
RoleModeState,
|
|
30
30
|
ROLE_DISPLAY,
|
|
31
|
+
SYSTEM_PROMPT_HEADING,
|
|
31
32
|
allowed_modes_for_role,
|
|
32
33
|
build_model_user_prompt,
|
|
33
34
|
parse_mode_arg,
|
|
34
35
|
parse_role_arg,
|
|
35
36
|
set_mode,
|
|
36
37
|
set_role,
|
|
37
|
-
|
|
38
|
+
strip_injected_prompt,
|
|
38
39
|
)
|
|
39
40
|
from kiwi_tui.screens.file_browser import FileBrowserScreen
|
|
40
41
|
from kiwi_tui.screens.help import HelpScreen
|
|
@@ -3813,7 +3814,7 @@ class TermDashboardScreen(Screen):
|
|
|
3813
3814
|
show(f"Could not read the queue ({lines[0]}).", is_error=True)
|
|
3814
3815
|
return
|
|
3815
3816
|
# AutoCode prompts are stored with their role/mode lines; show what was typed.
|
|
3816
|
-
prompts = [
|
|
3817
|
+
prompts = [strip_injected_prompt(prompt) for prompt in found[0]]
|
|
3817
3818
|
if run_id == self.current_run_id:
|
|
3818
3819
|
self._waiting_locally()[:] = prompts
|
|
3819
3820
|
self._set_queued_count(len(prompts))
|
|
@@ -3827,7 +3828,7 @@ class TermDashboardScreen(Screen):
|
|
|
3827
3828
|
known = self._waiting_locally() if run_id == self.current_run_id else []
|
|
3828
3829
|
expected = known[number - 1] if number <= len(known) else None
|
|
3829
3830
|
is_expected = (
|
|
3830
|
-
(lambda stored:
|
|
3831
|
+
(lambda stored: strip_injected_prompt(stored).strip() == expected.strip())
|
|
3831
3832
|
if expected is not None else None
|
|
3832
3833
|
)
|
|
3833
3834
|
outcome: list[QueueRemoval] = []
|
|
@@ -3857,7 +3858,7 @@ class TermDashboardScreen(Screen):
|
|
|
3857
3858
|
if number <= len(known):
|
|
3858
3859
|
del known[number - 1]
|
|
3859
3860
|
self._set_queued_count(result.waiting)
|
|
3860
|
-
text = " ".join(
|
|
3861
|
+
text = " ".join(strip_injected_prompt(result.removed).split())
|
|
3861
3862
|
toast(
|
|
3862
3863
|
f"Removed: {text if len(text) <= 60 else text[:59] + '…'} ({result.waiting} waiting)",
|
|
3863
3864
|
title="/queue",
|
|
@@ -4537,8 +4538,10 @@ class TermDashboardScreen(Screen):
|
|
|
4537
4538
|
)
|
|
4538
4539
|
user_text = str(extracted_in or "").strip()
|
|
4539
4540
|
logger.info(f"user text : {user_text}")
|
|
4540
|
-
if is_autocode_run or
|
|
4541
|
-
user_text
|
|
4541
|
+
if is_autocode_run or SYSTEM_PROMPT_HEADING in user_text or (
|
|
4542
|
+
"Your Current Role is" in user_text and "autocode." in user_text
|
|
4543
|
+
):
|
|
4544
|
+
user_text = strip_injected_prompt(user_text)
|
|
4542
4545
|
|
|
4543
4546
|
logger.info(f"User Text after stripping : {user_text}")
|
|
4544
4547
|
assistant_text = None
|
|
@@ -14,7 +14,7 @@ from kiwi_tui.role_mode import (
|
|
|
14
14
|
parse_role_arg,
|
|
15
15
|
set_mode,
|
|
16
16
|
set_role,
|
|
17
|
-
|
|
17
|
+
strip_injected_prompt,
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
|
|
@@ -58,14 +58,14 @@ def test_first_prompt_injects_general_and_mode_lines() -> None:
|
|
|
58
58
|
state = RoleModeState() # default
|
|
59
59
|
model_prompt, new_state = build_model_user_prompt(state, raw_user_prompt="Hello")
|
|
60
60
|
|
|
61
|
-
assert
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
assert model_prompt == (
|
|
62
|
+
"Hello\n"
|
|
63
|
+
"\n"
|
|
64
|
+
"# System Prompt\n"
|
|
65
|
+
f"Your Current Role is : {DEFAULT_ROLE}. Use autocode.{DEFAULT_ROLE}.general skill and act accordingly.\n"
|
|
66
|
+
"Plus use this exact mode skill(only).\n"
|
|
67
|
+
f"autocode.{DEFAULT_ROLE}.{DEFAULT_MODE} skill"
|
|
65
68
|
)
|
|
66
|
-
assert "Plus extract this exact mode skill(only)." in model_prompt
|
|
67
|
-
assert f"autocode.{DEFAULT_ROLE}.{DEFAULT_MODE} skill" in model_prompt
|
|
68
|
-
assert model_prompt.endswith("Hello")
|
|
69
69
|
|
|
70
70
|
assert new_state.has_sent_model_prompt is True
|
|
71
71
|
assert new_state.role_changed is False
|
|
@@ -82,10 +82,10 @@ def test_role_change_forces_mode_build_and_triggers_injection_on_next_prompt() -
|
|
|
82
82
|
|
|
83
83
|
model_prompt, state3 = build_model_user_prompt(state2, raw_user_prompt="Next")
|
|
84
84
|
|
|
85
|
+
assert model_prompt.startswith("Next\n\n# System Prompt\n")
|
|
85
86
|
assert f"Your Current Role is : {ROLE_ZERO_TO_ONE_ENGINEER}." in model_prompt
|
|
86
|
-
assert "Plus
|
|
87
|
-
assert "autocode.zero-to-one-engineer.build skill"
|
|
88
|
-
assert model_prompt.endswith("Next")
|
|
87
|
+
assert "Plus use this exact mode skill(only)." in model_prompt
|
|
88
|
+
assert model_prompt.endswith("autocode.zero-to-one-engineer.build skill")
|
|
89
89
|
|
|
90
90
|
assert state3.role_changed is False
|
|
91
91
|
assert state3.mode_changed is False
|
|
@@ -98,9 +98,13 @@ def test_mode_change_triggers_only_mode_injection_not_general() -> None:
|
|
|
98
98
|
|
|
99
99
|
model_prompt, _ = build_model_user_prompt(state2, raw_user_prompt="Ping")
|
|
100
100
|
|
|
101
|
-
assert
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
assert model_prompt == (
|
|
102
|
+
"Ping\n"
|
|
103
|
+
"\n"
|
|
104
|
+
"# System Prompt\n"
|
|
105
|
+
"Plus use this exact mode skill(only).\n"
|
|
106
|
+
"autocode.senior-software-engineer.validate skill"
|
|
107
|
+
)
|
|
104
108
|
|
|
105
109
|
|
|
106
110
|
def test_x2se_disallows_plan_without_error() -> None:
|
|
@@ -112,20 +116,74 @@ def test_x2se_disallows_plan_without_error() -> None:
|
|
|
112
116
|
assert state2.mode == MODE_BUILD
|
|
113
117
|
|
|
114
118
|
|
|
115
|
-
def
|
|
119
|
+
def test_no_change_sends_prompt_without_system_prompt() -> None:
|
|
120
|
+
state = RoleModeState(has_sent_model_prompt=True)
|
|
121
|
+
model_prompt, _ = build_model_user_prompt(state, raw_user_prompt="Plain")
|
|
122
|
+
assert model_prompt == "Plain"
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_strip_injected_prompt_strips_trailing_general_and_mode_block() -> None:
|
|
126
|
+
injected = (
|
|
127
|
+
"Hello world\n"
|
|
128
|
+
"\n"
|
|
129
|
+
"# System Prompt\n"
|
|
130
|
+
f"Your Current Role is : {DEFAULT_ROLE}. Use autocode.{DEFAULT_ROLE}.general skill and act accordingly.\n"
|
|
131
|
+
"Plus use this exact mode skill(only).\n"
|
|
132
|
+
f"autocode.{DEFAULT_ROLE}.{DEFAULT_MODE} skill"
|
|
133
|
+
)
|
|
134
|
+
assert strip_injected_prompt(injected) == "Hello world"
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_strip_injected_prompt_strips_trailing_mode_only_block() -> None:
|
|
138
|
+
injected = (
|
|
139
|
+
"Ping\n"
|
|
140
|
+
"\n"
|
|
141
|
+
"# System Prompt\n"
|
|
142
|
+
"Plus use this exact mode skill(only).\n"
|
|
143
|
+
"autocode.senior-software-engineer.validate skill"
|
|
144
|
+
)
|
|
145
|
+
assert strip_injected_prompt(injected) == "Ping"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def test_strip_injected_prompt_round_trips_built_prompt() -> None:
|
|
149
|
+
raw = "first line\n\nsecond paragraph"
|
|
150
|
+
model_prompt, _ = build_model_user_prompt(RoleModeState(), raw_user_prompt=raw)
|
|
151
|
+
assert strip_injected_prompt(model_prompt) == raw
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def test_strip_injected_prompt_keeps_users_own_heading() -> None:
|
|
155
|
+
text = "# System Prompt\nthis is my own markdown"
|
|
156
|
+
assert strip_injected_prompt(text) == text
|
|
157
|
+
trailing = "notes\n\n# System Prompt\nmy own section"
|
|
158
|
+
assert strip_injected_prompt(trailing) == trailing
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def test_strip_injected_prompt_strips_leading_heading_block() -> None:
|
|
162
|
+
# Format briefly sent before the block moved below the user's text.
|
|
163
|
+
injected = (
|
|
164
|
+
"# System Prompt\n"
|
|
165
|
+
f"Your Current Role is : {DEFAULT_ROLE}. Use autocode.{DEFAULT_ROLE}.general skill and act accordingly.\n"
|
|
166
|
+
"Plus use this exact mode skill(only).\n"
|
|
167
|
+
f"autocode.{DEFAULT_ROLE}.{DEFAULT_MODE} skill\n"
|
|
168
|
+
"hello"
|
|
169
|
+
)
|
|
170
|
+
assert strip_injected_prompt(injected) == "hello"
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def test_strip_injected_prompt_strips_legacy_general_and_mode_block() -> None:
|
|
116
174
|
injected = (
|
|
117
175
|
f"Your Current Role is : {DEFAULT_ROLE}. Fetch autocode.{DEFAULT_ROLE}.general skill and act accordingly.\n"
|
|
118
176
|
"Plus extract this exact mode skill(only).\n"
|
|
119
177
|
f"autocode.{DEFAULT_ROLE}.{DEFAULT_MODE} skill\n"
|
|
120
178
|
"Hello world"
|
|
121
179
|
)
|
|
122
|
-
assert
|
|
180
|
+
assert strip_injected_prompt(injected) == "Hello world"
|
|
123
181
|
|
|
124
182
|
|
|
125
|
-
def
|
|
183
|
+
def test_strip_injected_prompt_strips_legacy_mode_only_block() -> None:
|
|
126
184
|
injected = (
|
|
127
185
|
"Plus extract this exact mode skill(only).\n"
|
|
128
186
|
"autocode.senior-software-engineer.validate skill\n"
|
|
129
187
|
"Ping"
|
|
130
188
|
)
|
|
131
|
-
assert
|
|
189
|
+
assert strip_injected_prompt(injected) == "Ping"
|
|
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
|
|
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
|
|
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
|
|
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
|