Spaces:
Running on Zero
Running on Zero
fix: tighten advisor command routing
Browse filesCo-authored-by: Codex <noreply@openai.com>
- hackathon_advisor/model_runtime.py +46 -9
- static/app.js +33 -0
- static/index.html +67 -82
- static/styles.css +94 -0
- tests/test_model_runtime.py +9 -3
hackathon_advisor/model_runtime.py
CHANGED
|
@@ -75,13 +75,53 @@ class RuleBasedPlanner:
|
|
| 75 |
output = '<function name="list_projects">{"sort":"likes"}</function>'
|
| 76 |
elif project_id:
|
| 77 |
output = f'<function name="get_project">{{"id":{_json_string(project_id)}}}</function>'
|
| 78 |
-
elif
|
| 79 |
output = '<function name="compare_ideas">{}</function>'
|
| 80 |
-
elif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
output = '<function name="make_plan">{}</function>'
|
| 82 |
-
elif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
output = '<function name="find_whitespace">{}</function>'
|
| 84 |
-
elif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
output = f'<function name="search_projects">{{"query":{_json_string(text)}}}</function>'
|
| 86 |
else:
|
| 87 |
title, pitch = idea_from_text(text)
|
|
@@ -412,11 +452,8 @@ def _wants_project_list(lower_text: str) -> bool:
|
|
| 412 |
return lower_text in exact_phrases or any(lower_text.startswith(prefix) for prefix in command_prefixes)
|
| 413 |
|
| 414 |
|
| 415 |
-
def
|
| 416 |
-
return any(
|
| 417 |
-
re.search(rf"(?<![a-z0-9]){re.escape(term)}(?![a-z0-9])", lower_text)
|
| 418 |
-
for term in terms
|
| 419 |
-
)
|
| 420 |
|
| 421 |
|
| 422 |
def _project_reference_id(text: str) -> str:
|
|
|
|
| 75 |
output = '<function name="list_projects">{"sort":"likes"}</function>'
|
| 76 |
elif project_id:
|
| 77 |
output = f'<function name="get_project">{{"id":{_json_string(project_id)}}}</function>'
|
| 78 |
+
elif _matches_command(lower, ("compare", "compare ideas", "choose", "rank", "rank ideas")):
|
| 79 |
output = '<function name="compare_ideas">{}</function>'
|
| 80 |
+
elif _matches_command(
|
| 81 |
+
lower,
|
| 82 |
+
(
|
| 83 |
+
"plan",
|
| 84 |
+
"make a plan",
|
| 85 |
+
"make a build plan",
|
| 86 |
+
"draft a plan",
|
| 87 |
+
"draft a build plan",
|
| 88 |
+
"build plan",
|
| 89 |
+
"roadmap",
|
| 90 |
+
"next step",
|
| 91 |
+
"milestone",
|
| 92 |
+
),
|
| 93 |
+
):
|
| 94 |
output = '<function name="make_plan">{}</function>'
|
| 95 |
+
elif _matches_command(
|
| 96 |
+
lower,
|
| 97 |
+
(
|
| 98 |
+
"gap",
|
| 99 |
+
"find gap",
|
| 100 |
+
"find a gap",
|
| 101 |
+
"find whitespace",
|
| 102 |
+
"write bolder",
|
| 103 |
+
"bolder",
|
| 104 |
+
"unwritten",
|
| 105 |
+
"make it more original",
|
| 106 |
+
"new direction",
|
| 107 |
+
),
|
| 108 |
+
):
|
| 109 |
output = '<function name="find_whitespace">{}</function>'
|
| 110 |
+
elif _matches_command(
|
| 111 |
+
lower,
|
| 112 |
+
(
|
| 113 |
+
"search",
|
| 114 |
+
"search for",
|
| 115 |
+
"find similar",
|
| 116 |
+
"similar",
|
| 117 |
+
"is this already",
|
| 118 |
+
"already built",
|
| 119 |
+
"check overlap",
|
| 120 |
+
"overlap",
|
| 121 |
+
"show echoes",
|
| 122 |
+
"echo",
|
| 123 |
+
),
|
| 124 |
+
):
|
| 125 |
output = f'<function name="search_projects">{{"query":{_json_string(text)}}}</function>'
|
| 126 |
else:
|
| 127 |
title, pitch = idea_from_text(text)
|
|
|
|
| 452 |
return lower_text in exact_phrases or any(lower_text.startswith(prefix) for prefix in command_prefixes)
|
| 453 |
|
| 454 |
|
| 455 |
+
def _matches_command(lower_text: str, phrases: tuple[str, ...]) -> bool:
|
| 456 |
+
return lower_text in phrases or any(lower_text.startswith(f"{phrase} ") for phrase in phrases)
|
|
|
|
|
|
|
|
|
|
| 457 |
|
| 458 |
|
| 459 |
def _project_reference_id(text: str) -> str:
|
static/app.js
CHANGED
|
@@ -89,6 +89,8 @@ document.querySelectorAll("[data-command]").forEach((button) => {
|
|
| 89 |
});
|
| 90 |
});
|
| 91 |
|
|
|
|
|
|
|
| 92 |
demoButton.addEventListener("click", async () => {
|
| 93 |
await loadDemoSession();
|
| 94 |
});
|
|
@@ -1204,6 +1206,37 @@ function clearTurnWatchdog() {
|
|
| 1204 |
}
|
| 1205 |
}
|
| 1206 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1207 |
// Coarse overall completion per stage, so the bar always advances even when token-level
|
| 1208 |
// progress is unknown (e.g. the rules backend, or the fast tool/writing stages).
|
| 1209 |
const STAGE_PROGRESS = { planning: 8, running_tool: 85, writing: 95 };
|
|
|
|
| 89 |
});
|
| 90 |
});
|
| 91 |
|
| 92 |
+
setupMenus();
|
| 93 |
+
|
| 94 |
demoButton.addEventListener("click", async () => {
|
| 95 |
await loadDemoSession();
|
| 96 |
});
|
|
|
|
| 1206 |
}
|
| 1207 |
}
|
| 1208 |
|
| 1209 |
+
function setupMenus() {
|
| 1210 |
+
document.querySelectorAll(".menu").forEach((menu) => {
|
| 1211 |
+
const trigger = menu.querySelector(".menu-trigger");
|
| 1212 |
+
const list = menu.querySelector(".menu-list");
|
| 1213 |
+
if (!trigger || !list) return;
|
| 1214 |
+
trigger.addEventListener("click", (event) => {
|
| 1215 |
+
event.stopPropagation();
|
| 1216 |
+
const willOpen = list.hidden;
|
| 1217 |
+
closeAllMenus();
|
| 1218 |
+
if (willOpen) {
|
| 1219 |
+
list.hidden = false;
|
| 1220 |
+
trigger.setAttribute("aria-expanded", "true");
|
| 1221 |
+
}
|
| 1222 |
+
});
|
| 1223 |
+
list.addEventListener("click", () => closeAllMenus()); // selecting an item closes the menu
|
| 1224 |
+
});
|
| 1225 |
+
document.addEventListener("click", () => closeAllMenus());
|
| 1226 |
+
document.addEventListener("keydown", (event) => {
|
| 1227 |
+
if (event.key === "Escape") closeAllMenus();
|
| 1228 |
+
});
|
| 1229 |
+
}
|
| 1230 |
+
|
| 1231 |
+
function closeAllMenus() {
|
| 1232 |
+
document.querySelectorAll(".menu-list").forEach((list) => {
|
| 1233 |
+
list.hidden = true;
|
| 1234 |
+
});
|
| 1235 |
+
document.querySelectorAll(".menu-trigger").forEach((trigger) => {
|
| 1236 |
+
trigger.setAttribute("aria-expanded", "false");
|
| 1237 |
+
});
|
| 1238 |
+
}
|
| 1239 |
+
|
| 1240 |
// Coarse overall completion per stage, so the bar always advances even when token-level
|
| 1241 |
// progress is unknown (e.g. the rules backend, or the fast tool/writing stages).
|
| 1242 |
const STAGE_PROGRESS = { planning: 8, running_tool: 85, writing: 95 };
|
static/index.html
CHANGED
|
@@ -132,91 +132,76 @@
|
|
| 132 |
</div>
|
| 133 |
|
| 134 |
<div class="toolbar command-row" aria-label="Advisor commands">
|
| 135 |
-
<button id="submit" class="btn btn-ink" type="submit" title="Score this idea">
|
| 136 |
<svg class="icon"><use href="#icon-quill"></use></svg>
|
| 137 |
-
|
| 138 |
-
</button>
|
| 139 |
-
<button
|
| 140 |
-
type="button"
|
| 141 |
-
class="btn"
|
| 142 |
-
data-command="write bolder and find whitespace"
|
| 143 |
-
title="Find an under-explored direction"
|
| 144 |
-
>
|
| 145 |
-
<svg class="icon"><use href="#icon-gap"></use></svg>
|
| 146 |
-
Gap
|
| 147 |
-
</button>
|
| 148 |
-
<button
|
| 149 |
-
type="button"
|
| 150 |
-
class="btn"
|
| 151 |
-
data-command="make a build plan"
|
| 152 |
-
title="Draft a build plan for the current idea"
|
| 153 |
-
>
|
| 154 |
-
<svg class="icon"><use href="#icon-plan"></use></svg>
|
| 155 |
-
Plan
|
| 156 |
-
</button>
|
| 157 |
-
<button
|
| 158 |
-
type="button"
|
| 159 |
-
class="btn"
|
| 160 |
-
data-command="compare ideas"
|
| 161 |
-
title="Compare saved ideas"
|
| 162 |
-
>
|
| 163 |
-
<svg class="icon"><use href="#icon-rank"></use></svg>
|
| 164 |
-
Compare
|
| 165 |
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
<span class="spacer"></span>
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
class="
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
title="Export the current page"
|
| 204 |
-
aria-label="Export current page as PNG"
|
| 205 |
-
disabled
|
| 206 |
-
>
|
| 207 |
-
<svg class="icon"><use href="#icon-download"></use></svg>
|
| 208 |
-
PNG
|
| 209 |
-
</button>
|
| 210 |
-
<button
|
| 211 |
-
type="button"
|
| 212 |
-
id="reset-session"
|
| 213 |
-
class="btn btn-ghost btn-icon"
|
| 214 |
-
title="Reset the session"
|
| 215 |
-
aria-label="Reset session"
|
| 216 |
-
>
|
| 217 |
-
<svg class="icon"><use href="#icon-reset"></use></svg>
|
| 218 |
-
<span class="sr-only">Reset</span>
|
| 219 |
-
</button>
|
| 220 |
</div>
|
| 221 |
</form>
|
| 222 |
|
|
|
|
| 132 |
</div>
|
| 133 |
|
| 134 |
<div class="toolbar command-row" aria-label="Advisor commands">
|
| 135 |
+
<button id="submit" class="btn btn-ink" type="submit" title="Score this idea against the map">
|
| 136 |
<svg class="icon"><use href="#icon-quill"></use></svg>
|
| 137 |
+
Score idea
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
</button>
|
| 139 |
+
|
| 140 |
+
<div class="menu" data-menu="actions">
|
| 141 |
+
<button
|
| 142 |
+
type="button"
|
| 143 |
+
id="actions-trigger"
|
| 144 |
+
class="btn menu-trigger"
|
| 145 |
+
aria-haspopup="true"
|
| 146 |
+
aria-expanded="false"
|
| 147 |
+
title="More advisor actions"
|
| 148 |
+
>
|
| 149 |
+
Actions
|
| 150 |
+
<span class="caret" aria-hidden="true">▾</span>
|
| 151 |
+
</button>
|
| 152 |
+
<div class="menu-list" id="actions-menu" role="menu" hidden>
|
| 153 |
+
<button type="button" class="menu-item" role="menuitem" data-command="write bolder and find whitespace">
|
| 154 |
+
<svg class="icon"><use href="#icon-gap"></use></svg>
|
| 155 |
+
<span class="mi-text"><strong>Find a gap</strong><small>An under-explored direction to try</small></span>
|
| 156 |
+
</button>
|
| 157 |
+
<button type="button" class="menu-item" role="menuitem" data-command="make a build plan">
|
| 158 |
+
<svg class="icon"><use href="#icon-plan"></use></svg>
|
| 159 |
+
<span class="mi-text"><strong>Make a plan</strong><small>Draft build steps for the current idea</small></span>
|
| 160 |
+
</button>
|
| 161 |
+
<button type="button" class="menu-item" role="menuitem" data-command="compare ideas">
|
| 162 |
+
<svg class="icon"><use href="#icon-rank"></use></svg>
|
| 163 |
+
<span class="mi-text"><strong>Compare ideas</strong><small>Rank the ideas on your board</small></span>
|
| 164 |
+
</button>
|
| 165 |
+
</div>
|
| 166 |
+
</div>
|
| 167 |
+
|
| 168 |
<span class="spacer"></span>
|
| 169 |
+
|
| 170 |
+
<div class="menu" data-menu="more">
|
| 171 |
+
<button
|
| 172 |
+
type="button"
|
| 173 |
+
id="more-trigger"
|
| 174 |
+
class="btn btn-ghost menu-trigger btn-icon"
|
| 175 |
+
aria-haspopup="true"
|
| 176 |
+
aria-expanded="false"
|
| 177 |
+
title="Export and session options"
|
| 178 |
+
aria-label="More options"
|
| 179 |
+
>
|
| 180 |
+
<span class="caret-dots" aria-hidden="true">⋯</span>
|
| 181 |
+
</button>
|
| 182 |
+
<div class="menu-list menu-list-right" id="more-menu" role="menu" hidden>
|
| 183 |
+
<button type="button" id="load-demo" class="menu-item" role="menuitem" aria-label="Load example idea board">
|
| 184 |
+
<svg class="icon"><use href="#icon-example"></use></svg>
|
| 185 |
+
Example board
|
| 186 |
+
</button>
|
| 187 |
+
<button type="button" id="export-notes" class="menu-item" role="menuitem" aria-label="Export build notes" disabled>
|
| 188 |
+
<svg class="icon"><use href="#icon-download"></use></svg>
|
| 189 |
+
Build notes
|
| 190 |
+
</button>
|
| 191 |
+
<button type="button" id="export-chapter" class="menu-item" role="menuitem" aria-label="Export idea-board chapter" disabled>
|
| 192 |
+
<svg class="icon"><use href="#icon-download"></use></svg>
|
| 193 |
+
Chapter
|
| 194 |
+
</button>
|
| 195 |
+
<button type="button" id="export-artifact" class="menu-item" role="menuitem" aria-label="Export current page as PNG" disabled>
|
| 196 |
+
<svg class="icon"><use href="#icon-download"></use></svg>
|
| 197 |
+
Page PNG
|
| 198 |
+
</button>
|
| 199 |
+
<button type="button" id="reset-session" class="menu-item menu-item-danger" role="menuitem" aria-label="Reset session">
|
| 200 |
+
<svg class="icon"><use href="#icon-reset"></use></svg>
|
| 201 |
+
Reset session
|
| 202 |
+
</button>
|
| 203 |
+
</div>
|
| 204 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
</div>
|
| 206 |
</form>
|
| 207 |
|
static/styles.css
CHANGED
|
@@ -1402,3 +1402,97 @@ textarea:disabled {
|
|
| 1402 |
transform: translateY(0);
|
| 1403 |
}
|
| 1404 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1402 |
transform: translateY(0);
|
| 1403 |
}
|
| 1404 |
}
|
| 1405 |
+
|
| 1406 |
+
/* Action / overflow menus (consolidate secondary buttons) */
|
| 1407 |
+
.menu {
|
| 1408 |
+
position: relative;
|
| 1409 |
+
display: inline-flex;
|
| 1410 |
+
}
|
| 1411 |
+
|
| 1412 |
+
.menu-trigger .caret {
|
| 1413 |
+
margin-left: 4px;
|
| 1414 |
+
font-size: 0.72em;
|
| 1415 |
+
}
|
| 1416 |
+
|
| 1417 |
+
.menu-trigger[aria-expanded="true"] {
|
| 1418 |
+
border-color: var(--ink-faint);
|
| 1419 |
+
}
|
| 1420 |
+
|
| 1421 |
+
.caret-dots {
|
| 1422 |
+
font-size: 1.05rem;
|
| 1423 |
+
line-height: 1;
|
| 1424 |
+
letter-spacing: 1px;
|
| 1425 |
+
}
|
| 1426 |
+
|
| 1427 |
+
.menu-list {
|
| 1428 |
+
position: absolute;
|
| 1429 |
+
top: calc(100% + 6px);
|
| 1430 |
+
left: 0;
|
| 1431 |
+
z-index: 30;
|
| 1432 |
+
min-width: 210px;
|
| 1433 |
+
display: flex;
|
| 1434 |
+
flex-direction: column;
|
| 1435 |
+
gap: 2px;
|
| 1436 |
+
padding: 5px;
|
| 1437 |
+
background: var(--paper-3);
|
| 1438 |
+
border: 1px solid var(--edge);
|
| 1439 |
+
border-radius: 9px;
|
| 1440 |
+
box-shadow: 0 12px 30px -12px rgba(0, 0, 0, 0.45);
|
| 1441 |
+
}
|
| 1442 |
+
|
| 1443 |
+
.menu-list[hidden] {
|
| 1444 |
+
display: none;
|
| 1445 |
+
}
|
| 1446 |
+
|
| 1447 |
+
.menu-list-right {
|
| 1448 |
+
left: auto;
|
| 1449 |
+
right: 0;
|
| 1450 |
+
}
|
| 1451 |
+
|
| 1452 |
+
.menu-item {
|
| 1453 |
+
display: flex;
|
| 1454 |
+
align-items: center;
|
| 1455 |
+
gap: 9px;
|
| 1456 |
+
width: 100%;
|
| 1457 |
+
padding: 8px 10px;
|
| 1458 |
+
border: 0;
|
| 1459 |
+
border-radius: 6px;
|
| 1460 |
+
background: transparent;
|
| 1461 |
+
color: var(--ink);
|
| 1462 |
+
font: inherit;
|
| 1463 |
+
text-align: left;
|
| 1464 |
+
cursor: pointer;
|
| 1465 |
+
transition: background 0.15s ease;
|
| 1466 |
+
}
|
| 1467 |
+
|
| 1468 |
+
.menu-item:hover:not(:disabled),
|
| 1469 |
+
.menu-item:focus-visible:not(:disabled) {
|
| 1470 |
+
background: rgba(73, 49, 22, 0.09);
|
| 1471 |
+
outline: none;
|
| 1472 |
+
}
|
| 1473 |
+
|
| 1474 |
+
.menu-item:disabled {
|
| 1475 |
+
opacity: 0.42;
|
| 1476 |
+
cursor: default;
|
| 1477 |
+
}
|
| 1478 |
+
|
| 1479 |
+
.menu-item .icon {
|
| 1480 |
+
flex: 0 0 auto;
|
| 1481 |
+
color: var(--ink-soft);
|
| 1482 |
+
}
|
| 1483 |
+
|
| 1484 |
+
.menu-item .mi-text {
|
| 1485 |
+
display: flex;
|
| 1486 |
+
flex-direction: column;
|
| 1487 |
+
line-height: 1.25;
|
| 1488 |
+
}
|
| 1489 |
+
|
| 1490 |
+
.menu-item .mi-text small {
|
| 1491 |
+
color: var(--ink-faint);
|
| 1492 |
+
font-size: 0.72em;
|
| 1493 |
+
}
|
| 1494 |
+
|
| 1495 |
+
.menu-item-danger:hover:not(:disabled) {
|
| 1496 |
+
background: rgba(154, 43, 34, 0.1);
|
| 1497 |
+
color: var(--oxblood);
|
| 1498 |
+
}
|
tests/test_model_runtime.py
CHANGED
|
@@ -97,13 +97,19 @@ def test_rule_planner_keeps_project_words_inside_ideas() -> None:
|
|
| 97 |
def test_rule_planner_does_not_match_commands_inside_idea_words() -> None:
|
| 98 |
planner = RuleBasedPlanner()
|
| 99 |
|
| 100 |
-
|
| 101 |
"A neighborhood seed swap archive that reminds gardeners when to plant shared seeds",
|
| 102 |
{},
|
| 103 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
|
| 105 |
-
assert
|
| 106 |
-
assert
|
|
|
|
|
|
|
| 107 |
|
| 108 |
|
| 109 |
def test_rule_planner_splits_explicit_idea_pitch() -> None:
|
|
|
|
| 97 |
def test_rule_planner_does_not_match_commands_inside_idea_words() -> None:
|
| 98 |
planner = RuleBasedPlanner()
|
| 99 |
|
| 100 |
+
planting = planner.plan(
|
| 101 |
"A neighborhood seed swap archive that reminds gardeners when to plant shared seeds",
|
| 102 |
{},
|
| 103 |
)
|
| 104 |
+
cooking_plan = planner.plan(
|
| 105 |
+
"A countertop helper that turns pantry leftovers into a weekly cooking plan",
|
| 106 |
+
{},
|
| 107 |
+
)
|
| 108 |
|
| 109 |
+
assert planting.status == "valid"
|
| 110 |
+
assert planting.call.name == "save_idea"
|
| 111 |
+
assert cooking_plan.status == "valid"
|
| 112 |
+
assert cooking_plan.call.name == "save_idea"
|
| 113 |
|
| 114 |
|
| 115 |
def test_rule_planner_splits_explicit_idea_pitch() -> None:
|