mirror of
https://github.com/unslothai/unsloth.git
synced 2026-08-16 12:24:06 +00:00
* Fix CI on main: stale test doubles, a stale router stub, and two source defects
main has been red since Aug 14 and every open PR inherits it. Five clusters, none
of them caused by the PRs that were showing them.
context_length (13 tests, plus 4 more in disguise). #8700 added an unguarded
llama_backend.context_length read to the chat-completions path and updated five
test files, missing three. The real LlamaCppBackend has had the property for a
long time, so no user was ever affected; the doubles were simply
under-specified. The four gguf_stream_slot_release failures are the SAME bug:
those doubles reach the same line, but the AttributeError is swallowed into the
response task and surfaces as a 20 second timeout, which reads as a flake.
Nine hand-written doubles across five files each re-declared the same attribute
block with no shared base, so one new read broke whichever files happened not to
be updated. They now share FakeLlamaCppBackend, and a canary drives the real
route with a bare double so the next such read fails in one place, named, at the
point of the change. The stream waits no longer discard the driving task's
exception, so that class of failure cannot present as a bare timeout again.
youtube_router (2 tests). routes/__init__.py exports it and main.py imports it;
the app is fine. test_desktop_auth stubs sys.modules[routes] with a hardcoded
list of 17 routers, deliberately, to avoid importing the ML stack. #8648 added a
router and did not update it, the second time this has happened after
openai_codex_auth_router in #8511. The stub is now derived from main.py's own
import block, so it cannot go stale.
Repo tests (CPU), 6 failures, of which two are real source defects:
llama-extra-args.ts put the Studio brand into a user-visible validation message,
which the desktop branding contract forbids in runtime surfaces, and
test_playwright_server_lifecycle.py read checked-in files without an encoding,
which is a real Windows cp1252 crash the lint exists to catch. Both fixed in the
source. The other four are stale assertions chasing text that #8702 legitimately
moved or reflowed; they now assert the behaviour instead, via the real
override_lookup_candidates() and the element-scan pattern their own siblings
already use.
Not addressed here: pip scan-packages :: hf-stack reports 173 findings in
third-party deps under SCAN_ENFORCE=1 and is red on main too. Baselining a
supply-chain scanner to get green is the wrong reflex, so it wants its own look.
* Studio: break the settings/chat import cycle that stopped the UI rendering
#8932 added SIDEBAR_ORGANIZATION_STORAGE_KEY to the @/features/chat barrel and
had general-tab.tsx read it back out of that barrel. The key is used at MODULE
scope, in the storage-key list, and the barrel is part of an import cycle that
reaches this file, so the binding is still in its temporal dead zone when the
list is built:
Cannot access 'SIDEBAR_ORGANIZATION_STORAGE_KEY' before initialization
That kills the whole module graph, so the page renders nothing. It is why
Frontend CI has been failing on main with a Playwright locator that finds no
elements, which reads as a flaky browser test rather than a module-init error.
Importing the key straight from its module breaks the cycle. Verified by
bisection with the real browser smoke: it passes at cfee13795 (before #8932),
fails on main with the TDZ error above, and passes again with this one-line
change. Typecheck clean, 2756 frontend tests pass.
#8932's own branch was already red with this exact failure before it merged.
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
* Security: fix the filesystem-enumeration false positives in scan-packages
The hf-stack shard of pip scan-packages has been red on main. One CRITICAL
was blocking it, and tracking it down turned up a pattern bug behind nine of
the entries already in the baseline.
The blocking finding, unsloth-zoo/llama_cpp.py under "Harvests environment
variables/secrets AND makes network calls", is first-party: _github_auth_headers()
reads GH_TOKEN so the llama.cpp releases API call is not rate limited. That
file and check were already reviewed and baselined. It reopened because
unsloth-zoo 2026.8.12 replaced
keynames = "\n" + "\n".join(os.environ.keys())
with a targeted _is_colab_environment() helper. Every other matched line is
byte identical to what was reviewed, so the current code is a strict subset of
the approved evidence. The entry is refreshed, with the hash generated by
--write-baseline rather than by hand. No PR caused this; it is the baseline's
reopen-on-change working as designed against an upstream release.
The pattern bug is in RE_FS_ENUM:
r"|\bhistory\b.*\bread\b" # reading shell history
Under re.DOTALL that .* spans the whole file, so any module containing the
word "history" anywhere before the word "read" anywhere is filesystem
enumeration, and with a network call in the same file that is a CRITICAL.
That is httpx's Response.history, retries.history in urllib3, IPython's
history module, torch's CUDA memory history. Nine of the eleven baselined
CRITICALs under this check were that one alternative, each suppressing a whole
file for the check.
Meanwhile the precise half was dead. \b\.bash_history\b puts \b between "/"
and "." in "~/.bash_history", where neither side is a word character, so it
could never match; same for \b\.zsh_history\b. This is the unsatisfiable-\b
bug already fixed once for /proc/self/status. Checked against the old pattern:
it matched none of five real history-file reads and all four benign cases.
Naming the files instead inverts that. The nine dead baseline entries are
removed, which narrows the allowlist rather than widening it, and three tests
pin both directions.
Verified by running all three shards locally against the same requirements
transform CI uses: hf-stack now exits 0 (was 1), studio and extras stay at 0,
and no removed entry resurfaced.
* Fix two more stale sidebar contract tests left by #8932
Both fail on pristine origin/main, so they are not from this branch. #8932
moved the sidebar's user-visible copy into the locale file and rewrote the
delete-switch predicate to cover its new bulk targets. Neither change breaks a
contract; both broke a grep of app-sidebar.tsx.
test_the_delete_switch_does_not_promise_project_files greps for the sentence
"This chat's own sandbox folder is removed from disk." It is still there,
verbatim, in studio/frontend/src/i18n/locales/en.ts. The promise is the
contract, not its address, so the test now searches the frontend sources and
survives the next move while still failing on a reworded promise.
test_the_delete_switch_reaches_a_chat_moved_into_a_project pinned one spelling
of deleteTargetHasFiles:
-return target.kind === "project" || target.kind === "chat";
+return target.kind !== "run";
Same answer for a chat and for a project, plus the new "chats" / "projects"
bulk kinds. What must hold is that a run is excluded and that project
membership is never consulted, so the test reads the brace-matched function
body and asserts that instead of the old one-liner.
Both were checked by mutation: reinstating the misleading copy, and gating
deleteTargetHasFiles on target.item.projectId, each fail the rewritten test.
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
* Address the review: scope a contract test, keep a parity check, close a scanner gap
Four items, all confirmed against the code at head before changing anything.
1. tests/studio/test_model_picker_contracts.py: the rollback ordering assertion
searched the whole of chat-page.tsx, which takes the same snapshot in the hub
auto-load path at line 2558. The only applyModelLoadConfigToRuntime call is at
3262, so the index comparison was satisfied by the unrelated occurrence: deleting
the snapshot inside selectWithConfig outright still passed both assertions.
Verified by mutation. Now scoped to the selectWithConfig body, which fails on
that deletion.
2. studio/backend/tests/test_research_internal_call_tool_gate.py: dropping
perf_callback from the kwargs comparison hid presence as well as identity, so the
opt-out losing its callback on one path would have gone unnoticed and cost that
path its tok/s readout. Assert both are callable (or both absent) first, then
exclude. Verified by mutation at routes/inference.py:14512.
3. tests/studio/test_model_picker_contracts.py was source-only and ran without the
backend environment; calling the real ladder for a standalone .gguf pulled in
hub.utils.gguf, then loggers, then structlog, so a bare pytest run failed after
183 passes. CI installs studio.txt and is unaffected, so coverage there is
unchanged. The helper now skips on a missing third-party package only; a missing
first-party module still fails.
4. scripts/scan_packages.py: fish stores history at $XDG_DATA_HOME/fish/fish_history
with no leading dot (fishshell.com/docs/current/cmds/history.html), so the dotted
alternative could never match the real path and narrowing the pattern left an
exfiltration blind spot. Added a non-dotted form. The fish read plus a network call
is a CRITICAL again, the dotted shells still match, and the false positives stay
suppressed.
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
* Tighten comments added by the CI repair
* Fix two more stale studio contract constants left by #8932
Both fail on pristine origin/main, so neither comes from this branch, and in
both the source is right and the test-side constant is stale.
INLINE_ROW_IDS in tests/studio/playwright_mac_tab_capabilities.py still listed
four rows. #7863 had put Video under "More" as layout v5, so the script dropped
it: an unpinned row renders no data-testid and every assertion on it silently
observes nothing. #8932 pins Video under Images again, and records it in the
migration history as v7, so it is deliberate and versioned rather than an
accidental revert. Video is observable again, so the script samples it again.
test_inline_row_ids_match_the_frontends_default_pinned_set exists precisely to
catch this tuple drifting from the store in either direction, and it did its job.
test_multi_chat_prompt_queue_contract.py pinned the zero-argument spelling
"return await clearStoredChats();". #8932 gave the call an options argument,
which changes nothing about the ordering the assertion is there to hold, so it
now matches on the call prefix, the same way the sibling assertion three lines
up already does.
Both mutation-checked: unpinning Video in the store fails the first, and moving
requestPromptQueueStop after clearStoredChats fails the second.
* Narrow a contract search I made too wide, and read it once
Self-audit of an earlier fix in this branch, under the same standard applied to
everything else here.
test_the_delete_switch_does_not_promise_project_files greps for a promise the
delete dialog must make. #8932 moved that copy into the locale file, so the
original grep of app-sidebar.tsx broke, and my fix widened the search to the
whole frontend tree. That is the same defect the review caught in the rollback
ordering assertion: a search wide enough to be satisfied by an unrelated
occurrence proves nothing. The sentence appearing in any of ~1200 files, a
comment or a dead module included, would have passed it.
Now scoped by intent. The promise the dialog MUST make is looked for where the
sidebar's user-visible copy lives, the locales and the component. The promise it
must NOT make is still looked for across all of src, since breadth only makes a
negative stricter.
Mutation-checked: rewording the real string and planting the original in an
unrelated module fails the test, where the whole-tree form passed.
The two scopes are also read through an lru_cache. The wide one concatenates
about 1200 files, and it was re-reading every one of them on each call.
* Address the second review: real scoping, not the appearance of it
Five items, each reproduced against the code at head before changing anything.
Three are cases where my own earlier fix looked scoped but was not.
deleteTargetHasFiles: the negative assertions did not establish the contract.
`return target.kind === "run";` -- the exact inversion, which hides the delete
switch for every chat and project -- mentions "run", mentions no projectId, and
contains neither prohibited expression, so it passed all four checks. Confirmed
by construction. Now the direction is pinned: run is the kind excluded, never
the one included.
The selectWithConfig slice ran to end of file, not to the callback's closing
brace: 13,566 characters rather than 579. Moving applyModelLoadConfigToRuntime
out of the callback while leaving the snapshot behind still passed. Brace-matched
now, and that mutation fails.
asgi_stream_helpers returned on the frame without inspecting the task, so a
send() that sets the event and then raises left both futures done, the frame
branch won, and the caller's gather(return_exceptions = True) discarded the
exception. That is the silence the helper exists to break. Reproduced directly.
The task is checked first now, and the message says whether the failure came
before or after the frame.
Two scanner gaps, both from narrowing RE_FS_ENUM. Constructed fish paths put a
quote rather than a separator before the basename, so Path.home() / "fish" /
"fish_history" and os.path.join(h, "fish", "fish_history") did not match. And the
dotted list omitted PowerShell's ConsoleHost_history.txt, Ruby's .irb_history and
SQLite's .sqlite_history. A quote now counts as a boundary and those names are
covered, case-insensitively for the Windows one. Ten read forms match, and the
httpx, urllib3, IPython and torch false positives stay suppressed.
---------
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
820 lines
37 KiB
Python
820 lines
37 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-only
|
|
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
|
|
|
"""Static contracts for independent per-chat prompt queues."""
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
REPO = Path(__file__).resolve().parents[2]
|
|
FRONTEND = REPO / "studio/frontend/src"
|
|
THREAD = (FRONTEND / "components/assistant-ui/thread.tsx").read_text(encoding = "utf-8")
|
|
APP_SIDEBAR = (FRONTEND / "components/app-sidebar.tsx").read_text(encoding = "utf-8")
|
|
CHAT_ADAPTER = (FRONTEND / "features/chat/api/chat-adapter.ts").read_text(encoding = "utf-8")
|
|
MODEL_RUNTIME = (FRONTEND / "features/chat/hooks/use-chat-model-runtime.ts").read_text(
|
|
encoding = "utf-8"
|
|
)
|
|
CONFIRM_MODEL_SWAP = (FRONTEND / "features/chat/utils/confirm-stop-running-chats.ts").read_text(
|
|
encoding = "utf-8"
|
|
)
|
|
RUNTIME_PROVIDER = (FRONTEND / "features/chat/runtime-provider.tsx").read_text(encoding = "utf-8")
|
|
CHAT_RUNTIME_STORE = (FRONTEND / "features/chat/stores/chat-runtime-store.ts").read_text(
|
|
encoding = "utf-8"
|
|
)
|
|
CHAT_PAGE = (FRONTEND / "features/chat/chat-page.tsx").read_text(encoding = "utf-8")
|
|
SHARED_COMPOSER = (FRONTEND / "features/chat/shared-composer.tsx").read_text(encoding = "utf-8")
|
|
QUEUE_BOUNDARY = (FRONTEND / "features/chat/utils/prompt-queue-boundary.ts").read_text(
|
|
encoding = "utf-8"
|
|
)
|
|
QUEUED_MODEL_CAPABILITIES = (
|
|
FRONTEND / "features/chat/utils/queued-model-capabilities.ts"
|
|
).read_text(encoding = "utf-8")
|
|
PRE_STREAM_RESERVATION = (FRONTEND / "features/chat/utils/pre-stream-run-reservation.ts").read_text(
|
|
encoding = "utf-8"
|
|
)
|
|
CHAT_CLEAR_BOUNDARY = (FRONTEND / "features/chat/utils/chat-history-clear-boundary.ts").read_text(
|
|
encoding = "utf-8"
|
|
)
|
|
CHAT_HISTORY_STORAGE = (FRONTEND / "features/chat/utils/chat-history-storage.ts").read_text(
|
|
encoding = "utf-8"
|
|
)
|
|
QUEUED_SETTINGS = (FRONTEND / "features/chat/utils/queued-chat-run-settings.ts").read_text(
|
|
encoding = "utf-8"
|
|
)
|
|
SIDEBAR_ITEMS = (FRONTEND / "features/chat/hooks/use-chat-sidebar-items.ts").read_text(
|
|
encoding = "utf-8"
|
|
)
|
|
CLEAR_ALL_CHATS = (FRONTEND / "features/chat/utils/clear-all-chats.ts").read_text(encoding = "utf-8")
|
|
STOP_CHAT_THREAD = (FRONTEND / "features/chat/utils/stop-chat-thread.ts").read_text(
|
|
encoding = "utf-8"
|
|
)
|
|
|
|
|
|
def _between(source: str, start: str, end: str) -> str:
|
|
assert start in source, f"missing start marker: {start}"
|
|
tail = source.split(start, 1)[1]
|
|
assert end in tail, f"missing end marker after {start}: {end}"
|
|
return tail.split(end, 1)[0]
|
|
|
|
|
|
def test_scheduler_dispatches_each_ready_chat_without_a_frontend_global_cap():
|
|
pump = _between(
|
|
THREAD,
|
|
"function pumpPromptQueues()",
|
|
"async function dispatchQueuedPrompt(",
|
|
)
|
|
assert "while (true)" in pump
|
|
assert pump.index("promptQueueDispatchingRunIds.add(run.id)") < pump.index(
|
|
"dispatchQueuedPrompt(run, item, run.generation)"
|
|
)
|
|
assert "PROMPT_QUEUE_GLOBAL_CONCURRENCY" not in THREAD
|
|
assert "promptQueueHasCapacity" not in THREAD
|
|
assert "const reservations = new Map<symbol" in PRE_STREAM_RESERVATION
|
|
assert "reservationByThreadId" in PRE_STREAM_RESERVATION
|
|
assert "let preStreamRunReservations = 0" not in PRE_STREAM_RESERVATION
|
|
|
|
|
|
def test_each_chat_queue_stays_sequential_and_targets_its_background_runtime():
|
|
target = _between(
|
|
THREAD,
|
|
"const createPromptQueueTarget = useCallback(",
|
|
"const dismissWaitToast",
|
|
)
|
|
state_handler = _between(
|
|
THREAD,
|
|
"function handlePromptQueueRunState(",
|
|
"function ensurePromptQueueSubscription(",
|
|
)
|
|
assert "runtime.threads.getById(id)" in target
|
|
assert "setActiveThreadId" not in target
|
|
assert "return runningIds.length > 0" not in THREAD
|
|
assert "isPromptQueueRunTargetRunning(run" in state_handler
|
|
assert "advancePromptQueue(run)" in state_handler
|
|
assert "promptQueueActiveRunIds.has(run.id)" in THREAD
|
|
assert "Boolean(getActivePromptQueueItem(run)?.dispatched)" in THREAD
|
|
append = _between(
|
|
THREAD,
|
|
"function appendQueuedPrompt(",
|
|
"async function targetHasIndexingDocuments(",
|
|
)
|
|
assert "schedulePromptQueueTargetStatePoll(run)" in append
|
|
indexing_probe = _between(
|
|
THREAD,
|
|
"async function targetHasIndexingDocuments(",
|
|
"function getActivePromptQueueItem(",
|
|
)
|
|
assert "const documents = await listThreadDocuments(threadId)" in indexing_probe
|
|
assert "catch {\n // A failed status probe" in indexing_probe
|
|
assert "return true;" in indexing_probe
|
|
|
|
|
|
def test_saved_queues_survive_navigation_but_abandoned_temporary_queues_stop():
|
|
saved_switch = _between(
|
|
RUNTIME_PROVIDER,
|
|
"function ThreadAutoSwitch(",
|
|
"function ThreadNewChatSwitch(",
|
|
)
|
|
temporary_switch = _between(
|
|
RUNTIME_PROVIDER,
|
|
"function ThreadNewChatSwitch(",
|
|
"function ActiveThreadSync(",
|
|
)
|
|
assert "requestPromptQueueStop" not in saved_switch
|
|
assert "requestTemporaryPromptQueueStop()" in saved_switch
|
|
assert "switchToThread(threadId)" in saved_switch
|
|
assert "requestTemporaryPromptQueueStop()" in temporary_switch
|
|
assert "switchToNewThread()" in temporary_switch
|
|
|
|
temporary_toggle = _between(
|
|
CHAT_PAGE,
|
|
"const toggleIncognito = useCallback(",
|
|
"const hydratePersistedSettings",
|
|
)
|
|
assert "if (wasIncognito)" in temporary_toggle
|
|
assert "requestTemporaryPromptQueueStop()" in temporary_toggle
|
|
assert temporary_toggle.index("requestTemporaryPromptQueueStop()") < temporary_toggle.index(
|
|
"if (onEmptyScratchChat) return"
|
|
)
|
|
cancel_registrar = _between(
|
|
RUNTIME_PROVIDER,
|
|
"function CancelRegistrar()",
|
|
"function ThreadBackendAutosave(",
|
|
)
|
|
assert "thread?.getState().isRunning" in cancel_registrar
|
|
assert "unsubscribe = thread.subscribe(" in cancel_registrar
|
|
assert "threadListItem.remoteId" in cancel_registrar
|
|
assert "registerThreadCancel(threadId, cancel)" in cancel_registrar
|
|
assert "clearThreadCancel(threadId, cancel)" in cancel_registrar
|
|
assert cancel_registrar.index("thread.subscribe(") < cancel_registrar.rindex(
|
|
"clearThreadCancel(threadId, cancel)"
|
|
)
|
|
assert "state.cancelByThreadId[threadId] !== cancel" in CHAT_RUNTIME_STORE
|
|
|
|
|
|
def test_composer_only_queues_behind_the_current_chat():
|
|
submit = _between(
|
|
THREAD,
|
|
"const handleSubmit = useCallback(",
|
|
"const stopQueue = useCallback(",
|
|
)
|
|
assert "aui.thread().getState().isRunning" in submit
|
|
assert "usePromptQueueUI.getState()" in submit
|
|
assert "livePreStreamRunActive" in submit
|
|
assert "liveThreadIsRunning || livePreStreamRunActive" in submit
|
|
assert "startHydratedPromptQueue(" in submit
|
|
assert "aui.composer().getState().text.trim() !== queuedPrompt" in submit
|
|
assert "promptQueueStartPendingRef.current" in THREAD
|
|
assert "promptQueueStartPendingRef.current.has(reservationKey)" in THREAD
|
|
assert "promptQueueStartPendingRef.current.delete(reservationKey)" in THREAD
|
|
assert "promptQueueStartPendingRef.current.set(reservationKey, reservation)" in THREAD
|
|
assert "temporary: useChatRuntimeStore.getState().incognito" in THREAD
|
|
assert "localPromptQueueModelBoundary.capture()" in THREAD
|
|
assert "shouldAbortPendingQueueForModelBoundary" in THREAD
|
|
assert "queuedSettingsEpoch:" in THREAD
|
|
assert "shouldAbortPendingQueueForSettingsChange" in THREAD
|
|
assert "capturedEpoch: reservation.queuedSettingsEpoch" in THREAD
|
|
assert "currentEpoch: currentQueueSettings.queuedSettingsEpoch" in THREAD
|
|
assert "capturedTemporary: reservation.temporary" in THREAD
|
|
assert "currentTemporary: currentQueueSettings.incognito" in THREAD
|
|
assert "!settingsInvalidated" in THREAD
|
|
assert "reservation.cancelled = true" in THREAD
|
|
assert "temporaryOnly && !reservation.temporary" in THREAD
|
|
assert "onAborted?.()" in THREAD
|
|
assert 'toast.info("Saved list was not queued"' in THREAD
|
|
assert ".finally(() =>" in THREAD
|
|
assert "anyPromptQueueRunning" not in submit
|
|
assert "promptQueueAtCapacity" not in submit
|
|
assert "sendReservedComposer();" in submit
|
|
assert "reservePreStreamRun(preStreamThreadIds, {" in THREAD
|
|
assert "usesLocalModel:" in THREAD
|
|
assert "aui.threads().__internal_getAssistantRuntime?.()" in THREAD
|
|
assert "threads.getById(reservedThreadId).cancelRun()" in THREAD
|
|
assert "adoptPreStreamRunReservation(token, preStreamThreadIds)" in THREAD
|
|
assert "hasPreStreamRunReservation(getQueueThreadIds())" in THREAD
|
|
append_failure = _between(
|
|
THREAD,
|
|
"function handleQueuedPromptAppendFailure(",
|
|
"function consumePromptQueueDeepResearch(",
|
|
)
|
|
terminal_failure = append_failure.split(
|
|
"if (item.dispatchRetries > PROMPT_QUEUE_MAX_DISPATCH_RETRIES)", 1
|
|
)[1]
|
|
assert terminal_failure.index("item.target.cancel();") < terminal_failure.index(
|
|
"deletePromptQueueRun(run);"
|
|
)
|
|
assert terminal_failure.index("deletePromptQueueRun(run);") < terminal_failure.index(
|
|
"item.target.complete();"
|
|
)
|
|
assert "releaseCurrentPreStreamRun();" in CHAT_ADAPTER
|
|
assert "releasePreStreamRunReservation(reservationToken)" in CHAT_ADAPTER
|
|
assert "class PreStreamAwareAttachmentAdapter" in RUNTIME_PROVIDER
|
|
assert "preStreamRunThreadIdsForRuntime(" in RUNTIME_PROVIDER
|
|
attachment_adapter = _between(
|
|
RUNTIME_PROVIDER,
|
|
"const attachments = useMemo(",
|
|
"const adapters = useMemo(",
|
|
)
|
|
assert "[state.remoteId, state.id]" in attachment_adapter
|
|
assert "useChatRuntimeStore.getState().activeThreadId" in attachment_adapter
|
|
assert "preStreamRunThreadIdsForAdapter(" in CHAT_ADAPTER
|
|
adapter_wrapper = CHAT_ADAPTER.rsplit("async *run(args)", 1)[1]
|
|
assert "args.unstable_threadId," in adapter_wrapper
|
|
assert "useChatRuntimeStore.getState().activeThreadId" in adapter_wrapper
|
|
|
|
persisted_wrapper = _between(
|
|
RUNTIME_PROVIDER,
|
|
"function createPersistedRunAdapter(",
|
|
"function useStudioRuntimeAdapters(",
|
|
)
|
|
assert persisted_wrapper.index(
|
|
"const trackedRunStartThreadIds = runStartThreadIdsForMessages("
|
|
) < persisted_wrapper.index("findPreStreamRunReservation(reservationThreadIds)")
|
|
assert "[options.unstable_threadId, ...trackedRunStartThreadIds]" in persisted_wrapper
|
|
assert "findPreStreamRunReservation(reservationThreadIds)" in persisted_wrapper
|
|
assert "await waitForRunStartHistoryAppend(options.messages)" in persisted_wrapper
|
|
assert "releasePreStreamRunReservation(reservationToken)" in persisted_wrapper
|
|
assert "notifyPromptQueueRunFailed(" in persisted_wrapper
|
|
persisted_failure = _between(
|
|
persisted_wrapper,
|
|
"} catch (error) {",
|
|
"throw error;",
|
|
)
|
|
assert persisted_failure.index("releasePreStreamRunReservation(reservationToken)") < (
|
|
persisted_failure.index("notifyPromptQueueRunFailed(")
|
|
)
|
|
assert re.search(
|
|
r"releasePreStreamRunReservation\(reservationToken\);\s*}\s*"
|
|
r"//.*?notifyPromptQueueRunFailed\(",
|
|
persisted_failure,
|
|
re.S,
|
|
), "queue failure notification must not depend on a direct-send reservation"
|
|
|
|
|
|
def test_queued_settings_are_thread_scoped_without_cross_chat_fallback():
|
|
target = _between(
|
|
THREAD,
|
|
"const createPromptQueueTarget = useCallback(",
|
|
"const dismissWaitToast",
|
|
)
|
|
assert "await useChatRuntimeStore.getState().hydratePersistedSettings()" in target
|
|
assert target.index(
|
|
"await useChatRuntimeStore.getState().hydratePersistedSettings()"
|
|
) < target.index("snapshotQueuedChatRunSettings(chatStateAtQueueStart)")
|
|
assert "!promptQueueTargetMountedRef.current" in target
|
|
assert "const currentState = aui.threadListItem().getState()" in target
|
|
assert "initialRunningThreadIds.includes(id)" in target
|
|
assert "snapshotQueuedChatRunSettings(chatStateAtQueueStart)" in target
|
|
assert "registerQueuedChatRunSettings(" in target
|
|
assert "params: { ...runSettingsAtQueueStart.params }" in target
|
|
assert "runSettingsAtQueueStart.deepResearchEnabled = false" in target
|
|
assert target.index("const appendResult = thread.append(") < target.index(
|
|
"runSettingsAtQueueStart.deepResearchEnabled = false"
|
|
)
|
|
assert "void (appendResult as Promise<void>).catch(() => undefined)" in target
|
|
assert "function consumePromptQueueDeepResearch(" in THREAD
|
|
assert "!item.target.usesDeepResearch" in THREAD
|
|
assert ".then(() => consumePromptQueueDeepResearch(run, item))" in THREAD
|
|
assert "usesDeepResearch: runSettingsAtQueueStart.deepResearchEnabled" in target
|
|
assert "if (existingRun.deepResearchConsumed)" in THREAD
|
|
assert "addQueuedChatRunSettingsThreadIds(settingsId" in target
|
|
assert ".getItemById(state.id)\n .initialize()" in target
|
|
assert "await updateStoredChatThread(remoteId" in target
|
|
assert "let shouldCorrectPersistedModel: boolean | null = null" in target
|
|
assert "shouldCorrectPersistedModel ??= !state.remoteId" in target
|
|
assert "if (shouldCorrectPersistedModel)" in target
|
|
assert (
|
|
target.index("await updateStoredChatThread(remoteId")
|
|
< target.index("shouldCorrectPersistedModel = false")
|
|
< target.index("const appendResult = thread.append(")
|
|
)
|
|
assert 'modelId: runSettingsAtQueueStart.params.checkpoint ?? ""' in target
|
|
assert target.index("await updateStoredChatThread(remoteId") < target.index(
|
|
"const appendResult = thread.append("
|
|
)
|
|
assert (
|
|
target.index("addQueuedChatRunSettingsThreadIds(settingsId")
|
|
< target.index("syncPromptQueueUI()")
|
|
< target.index("const appendResult = thread.append(")
|
|
)
|
|
assert "let cancelled = false" in target
|
|
assert target.count("cancelled ||") >= 2
|
|
assert target.count("!pendingSettingsIds.has(settingsId)") >= 2
|
|
assert target.index("!pendingSettingsIds.has(settingsId)") < target.index(
|
|
"const appendResult = thread.append("
|
|
)
|
|
assert "cancelled = true" in target
|
|
assert "isTargetCurrentThread() &&" in target
|
|
assert "consumeQueuedChatRunSettings(resolvedThreadId)" in CHAT_ADAPTER
|
|
assert '"deepResearchEnabled"' in QUEUED_SETTINGS
|
|
assert '"supportsReasoning"' in QUEUED_SETTINGS
|
|
assert '"reasoningAlwaysOn"' in QUEUED_SETTINGS
|
|
assert '"reasoningStyle"' in QUEUED_SETTINGS
|
|
assert '"supportsReasoningOff"' in QUEUED_SETTINGS
|
|
assert '"reasoningEffortLevels"' in QUEUED_SETTINGS
|
|
assert '"supportsPreserveThinking"' in QUEUED_SETTINGS
|
|
assert '"researchWebsitePolicy"' in QUEUED_SETTINGS
|
|
assert CHAT_ADAPTER.index(
|
|
"consumeQueuedChatRunSettings(resolvedThreadId)"
|
|
) < CHAT_ADAPTER.index("if (runtime.deepResearchEnabled && threadAlreadyResearched)")
|
|
research = _between(
|
|
CHAT_ADAPTER,
|
|
"if (\n runtime.deepResearchEnabled",
|
|
"const sandboxSessionId",
|
|
)
|
|
assert "const liveRuntime = useChatRuntimeStore.getState()" in research
|
|
assert "...queuedRunSettings" in research
|
|
auto_load_merge = _between(
|
|
CHAT_ADAPTER,
|
|
"// Re-read store after auto-load / model-ready wait.",
|
|
"const { params } = runtime",
|
|
)
|
|
assert "...queuedRunSettings.params" in auto_load_merge
|
|
assert "queuedEmptyModelRuntime?.checkpoint" in auto_load_merge
|
|
assert "liveRuntime.params.checkpoint" in auto_load_merge
|
|
assert "liveRuntime.supportsTools" in auto_load_merge
|
|
assert "liveRuntime.supportsReasoning" in auto_load_merge
|
|
assert "liveRuntime.ggufContextLength" in auto_load_merge
|
|
assert "isExternalModelId(visibleState.params.checkpoint)" in CHAT_ADAPTER
|
|
assert "resolveInferenceCheckpointId(status)" in CHAT_ADAPTER
|
|
assert "skipAdoptServerModel: true" in CHAT_ADAPTER
|
|
assert "snapshotVisibleModelState(" in CHAT_ADAPTER
|
|
assert "restoreVisibleModelState(visibleExternalState)" in CHAT_ADAPTER
|
|
assert '"ggufContextLength"' in CHAT_ADAPTER
|
|
assert '"ggufMaxContextLength"' in CHAT_ADAPTER
|
|
assert '"ggufNativeContextLength"' in CHAT_ADAPTER
|
|
assert '"loadedIsMultimodal"' in CHAT_ADAPTER
|
|
assert '"loadedIsDiffusion"' in CHAT_ADAPTER
|
|
assert (
|
|
'"contextUsage"'
|
|
not in CHAT_ADAPTER[
|
|
CHAT_ADAPTER.index("const VISIBLE_MODEL_RUNTIME_KEYS") : CHAT_ADAPTER.index(
|
|
"] as const satisfies", CHAT_ADAPTER.index("const VISIBLE_MODEL_RUNTIME_KEYS")
|
|
)
|
|
]
|
|
)
|
|
assert "contextUsage: liveUsage.contextUsage" in CHAT_ADAPTER
|
|
assert "contextUsageByThreadId: liveUsage.contextUsageByThreadId" in CHAT_ADAPTER
|
|
assert "visibleState.activeThreadEpoch" in CHAT_ADAPTER
|
|
assert "activeThreadEpoch ===" in CHAT_ADAPTER
|
|
assert "visibleState.queuedSettingsEpoch" in CHAT_ADAPTER
|
|
assert "queuedSettingsEpoch ===" in CHAT_ADAPTER
|
|
assert "preserveVisibleSettings: true" in CHAT_ADAPTER
|
|
assert "captureResolvedRuntime: (runtime) =>" in CHAT_ADAPTER
|
|
assert "applyAutoLoadRuntimeState(options" in CHAT_ADAPTER
|
|
assert CHAT_ADAPTER.count("trackQueuedSettings: !options?.preserveVisibleSettings") >= 4
|
|
assert "const visibleRoute = window.location.href" in CHAT_ADAPTER
|
|
assert "window.location.href === visibleRoute" in CHAT_ADAPTER
|
|
assert "trackQueuedSettings: false" in CHAT_ADAPTER
|
|
assert CHAT_ADAPTER.count("await resolveQueuedEmptyLocalModel(abortSignal)") >= 2
|
|
assert "persist: !options?.preserveVisibleSettings" in CHAT_ADAPTER
|
|
assert "beginModelLoading()" in CHAT_ADAPTER
|
|
assert "endModelLoading(lifecycleLease)" in CHAT_ADAPTER
|
|
lifecycle = _between(
|
|
CHAT_ADAPTER,
|
|
"async function resolveQueuedEmptyLocalModel(",
|
|
"export function createOpenAIStreamAdapter",
|
|
)
|
|
assert lifecycle.index("beginModelLoading()") < lifecycle.index("await getInferenceStatus()")
|
|
assert lifecycle.index("await getInferenceStatus()") < lifecycle.index(
|
|
"await autoLoadSmallestModel("
|
|
)
|
|
assert "getInferenceStatus().catch(() => null)" not in lifecycle
|
|
assert "const status = await getInferenceStatus();" in lifecycle
|
|
assert "options?.abortSignal?.throwIfAborted()" in CHAT_ADAPTER
|
|
assert CHAT_ADAPTER.count("await persistResolvedQueuedModel(params.checkpoint)") >= 2
|
|
assert "notifyQueuedRunFailed" not in CHAT_ADAPTER
|
|
assert "pendingSettings.length === 1" not in QUEUED_SETTINGS
|
|
assert "entry.threadIds.has(threadId)" in QUEUED_SETTINGS
|
|
assert "return pendingSettings[index].settings" in QUEUED_SETTINGS
|
|
assert "pendingSettings.splice(index, 1)[0].settings" not in QUEUED_SETTINGS
|
|
assert "complete: discardOldestPendingSettings" in target
|
|
assert "getActivePromptQueueItem(run)?.target.complete()" in THREAD
|
|
assert "adapterRunStartedSignals" not in CHAT_ADAPTER
|
|
assert "pendingSettings.some((entry) => entry.threadIds.has(threadId))" in QUEUED_SETTINGS
|
|
queued_run_failure = _between(
|
|
CHAT_ADAPTER,
|
|
"try {\n yield* adapter.run(args);",
|
|
"} finally {",
|
|
)
|
|
assert "if (!args.abortSignal.aborted)" in queued_run_failure
|
|
assert queued_run_failure.index("notifyPromptQueueRunFailed(") < queued_run_failure.index(
|
|
"throw error;"
|
|
)
|
|
queue_failure_handler = _between(
|
|
THREAD,
|
|
"function handlePromptQueueRunFailed(",
|
|
'if (typeof window !== "undefined")',
|
|
)
|
|
assert "if (failedRun)" in queue_failure_handler
|
|
assert "retainPendingPromptQueueItemsAfterFailure(failedRun)" in queue_failure_handler
|
|
assert "deletePromptQueueRun(failedRun);" in queue_failure_handler
|
|
retained_failure = _between(
|
|
THREAD,
|
|
"function retainPendingPromptQueueItemsAfterFailure(run: PromptQueueRun)",
|
|
"function cancelPendingPromptQueueFactoriesForStop<",
|
|
)
|
|
assert retained_failure.index("activeItem.target.complete();") < retained_failure.index(
|
|
"run.items.splice(activeIndex, 1);"
|
|
)
|
|
assert "waitForPromptQueueTargetIdle(run);" in retained_failure
|
|
local_queue_stop = _between(
|
|
THREAD,
|
|
"function stopLocalPromptQueueRun(run: PromptQueueRun)",
|
|
"function stopLocalPromptQueueRunsForThreadIds(threadIds: string[])",
|
|
)
|
|
assert "if (plan.refreshTargetIdleWait)" in local_queue_stop
|
|
assert "refreshPromptQueueTargetIdleWait(run);" in local_queue_stop
|
|
assert "claimPreStreamRunReservation(reservationToken);" in RUNTIME_PROVIDER
|
|
assert "if (!reservation.claimed)" in PRE_STREAM_RESERVATION
|
|
assert "loadedIsMultimodal: isMultimodalResponse(status)" in lifecycle
|
|
assert "isAudio: status.is_audio ?? false" in lifecycle
|
|
assert "hasAudioInput: status.has_audio_input ?? false" in lifecycle
|
|
assert CHAT_ADAPTER.count("models: mergeQueuedModelCapabilities(") == 2
|
|
assert "modelIndex === index ? { ...model, ...capabilities } : model" in (
|
|
QUEUED_MODEL_CAPABILITIES
|
|
)
|
|
assert "loadedIsMultimodal: state.loadedIsMultimodal" in CHAT_ADAPTER
|
|
assert "queuedEmptyModelRuntime?.loadedIsMultimodal" in auto_load_merge
|
|
assert "usesLocalModel:" in target
|
|
assert "usePromptQueueUI.getState().byThreadId" in CONFIRM_MODEL_SWAP
|
|
assert "getLocalPromptQueueThreadIds" in CONFIRM_MODEL_SWAP
|
|
assert "promptQueueThreadIds" in MODEL_RUNTIME
|
|
assert MODEL_RUNTIME.count("requestLocalPromptQueueStop(") >= 4
|
|
assert MODEL_RUNTIME.index("requestLocalPromptQueueStop();") < MODEL_RUNTIME.index(
|
|
"const loadResponse = await loadModel("
|
|
)
|
|
eject = _between(
|
|
MODEL_RUNTIME,
|
|
"const ejectModel = useCallback(",
|
|
"return {",
|
|
)
|
|
select_model = _between(
|
|
MODEL_RUNTIME,
|
|
"const selectModel = useCallback(",
|
|
"const ejectModel = useCallback(",
|
|
)
|
|
assert (
|
|
select_model.index("beginModelLoading()")
|
|
< select_model.index("await confirmStopRunningChatsIfNeeded(")
|
|
< select_model.index("cancelPreStreamRunReservations(stopDecision.preStreamRunTokens)")
|
|
< select_model.index("requestLocalPromptQueueStop(stopDecision.promptQueueThreadIds)")
|
|
)
|
|
assert "beginModelLoading()" in eject
|
|
assert "endModelLoading(lifecycleLease)" in eject
|
|
assert "beginModelLoading()" in SHARED_COMPOSER
|
|
assert "endModelLoading(compareLifecycleLease)" in SHARED_COMPOSER
|
|
assert SHARED_COMPOSER.count("releaseCompareModelLifecycle();") >= 3
|
|
compare_upgrade = _between(
|
|
SHARED_COMPOSER,
|
|
"const upgraded = await confirmTransformersUpgradeIfNeeded({",
|
|
"});",
|
|
)
|
|
assert "forceCancelActive:" in compare_upgrade
|
|
assert "compareStopDecision?.forceCancelActive ?? false" in compare_upgrade
|
|
compare_handle = _between(
|
|
SHARED_COMPOSER,
|
|
"export function RegisterCompareHandle(",
|
|
"type PendingImage =",
|
|
)
|
|
assert "aui.threads().__internal_getAssistantRuntime?.()" in compare_handle
|
|
assert "runtime?.threads.getById(threadId)" in compare_handle
|
|
assert "thread.subscribe(" in compare_handle
|
|
assert "useChatRuntimeStore.subscribe(" not in compare_handle
|
|
gpu_discovery = _between(
|
|
SHARED_COMPOSER,
|
|
"// Warm the device cache before the snapshot below",
|
|
"// The GPU/offload knobs both compare loads must use",
|
|
)
|
|
assert "await ensureGpuDeviceCache();" in gpu_discovery
|
|
assert "catch (error) {\n releaseCompareModelLifecycle();" in gpu_discovery
|
|
side_one = _between(
|
|
SHARED_COMPOSER,
|
|
"// Side 1: load → generate → wait",
|
|
"// Side 2: load → generate → wait",
|
|
)
|
|
assert (
|
|
side_one.index("const status1 = await ensureModelLoaded(model1)")
|
|
< side_one.index("releaseCompareModelLifecycle();")
|
|
< side_one.index("handle1.startRun()")
|
|
)
|
|
side_two = _between(
|
|
SHARED_COMPOSER,
|
|
"// Side 2: load → generate → wait",
|
|
"compareStepSucceededRef.current = true",
|
|
)
|
|
assert (
|
|
side_two.index("acquireCompareModelLifecycle();")
|
|
< side_two.index("await confirmStopRunningChatsIfNeeded(")
|
|
< side_two.index("compareStopDecision = currentStopDecision")
|
|
< side_two.index("const status2 = await ensureModelLoaded(model2)")
|
|
< side_two.index("releaseCompareModelLifecycle();")
|
|
< side_two.index("handle2.startRun()")
|
|
)
|
|
assert "requestLocalPromptQueueStop" in eject
|
|
assert (
|
|
eject.index("beginModelLoading()")
|
|
< eject.index("await confirmStopRunningChatsIfNeeded(")
|
|
< eject.index("cancelPreStreamRunReservations(stopDecision.preStreamRunTokens)")
|
|
< eject.index("requestLocalPromptQueueStop(stopDecision.promptQueueThreadIds)")
|
|
)
|
|
assert "function promptQueueRunUsesLocalModel(run: PromptQueueRun)" in THREAD
|
|
assert ".slice(Math.max(run.index, 0))" in THREAD
|
|
assert ".some((item) => item.target.usesLocalModel)" in THREAD
|
|
assert "local: promptQueueRunUsesLocalModel(run)" in THREAD
|
|
assert "detail: { threadIds, localOnly: true }" in QUEUE_BOUNDARY
|
|
assert "stopLocalPromptQueueRunsForThreadIds(threadIds ?? [])" in THREAD
|
|
local_queue_stop = _between(
|
|
THREAD,
|
|
"function stopLocalPromptQueueRun(run: PromptQueueRun)",
|
|
"function stopLocalPromptQueueRunsForThreadIds(threadIds: string[])",
|
|
)
|
|
assert "planLocalPromptQueueStop(" in local_queue_stop
|
|
assert "activeItem?.target.cancel();" in local_queue_stop
|
|
assert "waitForPromptQueueTargetIdle(run);" in local_queue_stop
|
|
pending_factory_stop = _between(
|
|
THREAD,
|
|
"function cancelPendingPromptQueueFactoriesForStop<",
|
|
"function stopAllPromptQueueRuns()",
|
|
)
|
|
assert pending_factory_stop.index("if (localOnly)") < pending_factory_stop.index(
|
|
"for (const [key, reservation]"
|
|
)
|
|
assert "cancelPendingPromptQueueFactoriesForStop(" in THREAD
|
|
assert "temporary: incognitoAtQueueStart" in THREAD
|
|
assert "temporary: promptQueueRunIsTemporary(run)" in THREAD
|
|
assert "dispatched: Boolean(getActivePromptQueueItem(run)?.dispatched)" in THREAD
|
|
assert "queueEntry?.dispatched" in THREAD
|
|
assert 'aria-label="Stop queued message"' in THREAD
|
|
assert "entry.temporary" in QUEUE_BOUNDARY
|
|
assert "localPromptQueueModelBoundary.advance()" in QUEUE_BOUNDARY
|
|
assert "entry.local" in QUEUE_BOUNDARY
|
|
assert "queuedRunSettings.params.checkpoint" in CHAT_ADAPTER
|
|
persisted_adapter = _between(
|
|
RUNTIME_PROVIDER,
|
|
"function createPersistedRunAdapter(",
|
|
"function useStudioRuntimeAdapters(",
|
|
)
|
|
assert "const trackedRunStartThreadIds = runStartThreadIdsForMessages(" in persisted_adapter
|
|
assert "isPreStreamRunReservationCancelled(reservationToken)" in persisted_adapter
|
|
assert persisted_adapter.count("throwIfReservationCancelled();") == 2
|
|
assert persisted_adapter.index(
|
|
"requestPromptQueueStop(persistedRunThreadIds)"
|
|
) < persisted_adapter.index("notifyPromptQueueRunFailed(")
|
|
assert "pendingRunStartThreadIdsByMessageId" in RUNTIME_PROVIDER
|
|
assert "localThreadId," in RUNTIME_PROVIDER
|
|
successful_persisted_preflight = _between(
|
|
RUNTIME_PROVIDER,
|
|
"async function waitForRunStartHistoryAppend(",
|
|
"function createPersistedRunAdapter(",
|
|
)
|
|
assert successful_persisted_preflight.index(
|
|
"pendingRunStartReadyByMessageId.delete(userMessage.id)"
|
|
) < successful_persisted_preflight.index(
|
|
"pendingRunStartThreadIdsByMessageId.delete(userMessage.id)"
|
|
)
|
|
assert "!runningByThreadId[threadId] && !cancel" in STOP_CHAT_THREAD
|
|
assert "serverCancels.length === 0" in STOP_CHAT_THREAD
|
|
assert "await confirmStopRunningChatsIfNeeded(" in SHARED_COMPOSER
|
|
send_flow = _between(
|
|
SHARED_COMPOSER,
|
|
"async function send()",
|
|
"sendRef.current = send;",
|
|
)
|
|
assert "const submittedText = text;" in send_flow
|
|
assert "const submittedImages = pendingImages;" in send_flow
|
|
assert "const submittedAudio = pendingAudio;" in send_flow
|
|
assert "textRef.current === submittedText" in send_flow
|
|
assert "pendingImagesRef.current === submittedImages" in send_flow
|
|
assert "pendingAudioRef.current === submittedAudio" in send_flow
|
|
confirm_index = send_flow.index("await confirmStopRunningChatsIfNeeded(")
|
|
first_draft_check = send_flow.index("if (!submittedDraftIsCurrent())")
|
|
gpu_discovery_index = send_flow.index("await ensureGpuDeviceCache();")
|
|
second_draft_check = send_flow.index(
|
|
"if (!submittedDraftIsCurrent())",
|
|
gpu_discovery_index,
|
|
)
|
|
assert (
|
|
send_flow.index("beginModelLoading()")
|
|
< confirm_index
|
|
< first_draft_check
|
|
< gpu_discovery_index
|
|
< second_draft_check
|
|
< send_flow.index("clearSubmittedDraft();")
|
|
)
|
|
assert "requestLocalPromptQueueStop(" in SHARED_COMPOSER
|
|
assert "compareStopDecision?.preStreamRunTokens ?? []" in SHARED_COMPOSER
|
|
assert SHARED_COMPOSER.index("requestLocalPromptQueueStop(") < SHARED_COMPOSER.index(
|
|
"const resp = await loadModel("
|
|
)
|
|
apply_compare_stop = _between(
|
|
send_flow,
|
|
"const applyCompareStopDecision = () => {",
|
|
"// Helper: load a model and update store checkpoint",
|
|
)
|
|
assert "cancelPreStreamRunReservations(" in apply_compare_stop
|
|
assert "compareStopDecision?.preStreamRunTokens ?? []" in apply_compare_stop
|
|
assert "requestLocalPromptQueueStop(" in apply_compare_stop
|
|
assert "compareStopDecision?.promptQueueThreadIds" in apply_compare_stop
|
|
ensure_compare_model = _between(
|
|
send_flow,
|
|
"async function ensureModelLoaded(",
|
|
"// Side 1: load",
|
|
)
|
|
already_active = _between(
|
|
ensure_compare_model,
|
|
"if (isAlreadyActive && !config && !loadedFromConfig) {",
|
|
"}",
|
|
)
|
|
assert already_active.index("applyCompareStopDecision();") < already_active.index(
|
|
'return "ready";'
|
|
)
|
|
assert ensure_compare_model.count("applyCompareStopDecision();") == 2
|
|
validated_load_stop = ensure_compare_model.rindex("applyCompareStopDecision();")
|
|
assert (
|
|
ensure_compare_model.index("const validation = await validateModel(")
|
|
< validated_load_stop
|
|
< ensure_compare_model.index("const resp = await loadModel(")
|
|
)
|
|
assert "force_cancel_active:" in SHARED_COMPOSER
|
|
assert (
|
|
"resolvedThreadId ===\n useChatRuntimeStore.getState().activeThreadId"
|
|
in CHAT_ADAPTER
|
|
)
|
|
assert (
|
|
"findLatestUserAudioBase64(\n survivingMessages,\n !queuedRunSettings"
|
|
in CHAT_ADAPTER
|
|
)
|
|
assert "if (audioBase64 && !queuedRunSettings)" in CHAT_ADAPTER
|
|
assert ".setThreadContextUsage(usageThreadKey, usage)" in CHAT_ADAPTER
|
|
assert (
|
|
"usageThreadIsVisible &&\n"
|
|
" useChatRuntimeStore.getState().params.checkpoint === params.checkpoint"
|
|
in CHAT_ADAPTER
|
|
)
|
|
|
|
|
|
def test_compare_prompt_list_resets_when_preflight_never_starts_a_run():
|
|
reset = _between(
|
|
SHARED_COMPOSER,
|
|
"function resetPromptQueue()",
|
|
"function advanceQueue()",
|
|
)
|
|
assert "isQueueRunningRef.current = false;" in reset
|
|
assert "setIsQueueRunning(false);" in reset
|
|
assert "queueRef.current = [];" in reset
|
|
assert "queueIndexRef.current = 0;" in reset
|
|
assert "setQueueProgress({ current: 0, total: 0 });" in reset
|
|
|
|
send_flow = _between(
|
|
SHARED_COMPOSER,
|
|
"async function send()",
|
|
"sendRef.current = send;",
|
|
)
|
|
unavailable_lifecycle = _between(
|
|
send_flow,
|
|
"if (compareLifecycleLease === null)",
|
|
"const releaseCompareModelLifecycle = () =>",
|
|
)
|
|
assert "resetPromptQueue();" in unavailable_lifecycle
|
|
|
|
failed_preflight = _between(
|
|
send_flow,
|
|
"compareStopDecision = await confirmStopRunningChatsIfNeeded(",
|
|
"if (!compareStopDecision.proceed)",
|
|
)
|
|
assert "resetPromptQueue();" in failed_preflight
|
|
|
|
declined_preflight = _between(
|
|
send_flow,
|
|
"if (!compareStopDecision.proceed)",
|
|
"if (!submittedDraftIsCurrent())",
|
|
)
|
|
assert (
|
|
declined_preflight.index("releaseCompareModelLifecycle();")
|
|
< declined_preflight.index("resetPromptQueue();")
|
|
< declined_preflight.index("return;")
|
|
)
|
|
|
|
changed_draft = _between(
|
|
send_flow,
|
|
"const keepChangedDraft = () =>",
|
|
"const clearSubmittedDraft = () =>",
|
|
)
|
|
assert "releaseCompareModelLifecycle();" in changed_draft
|
|
assert "resetPromptQueue();" in changed_draft
|
|
|
|
failed_gpu_discovery = _between(
|
|
send_flow,
|
|
"// Warm the device cache before the snapshot below",
|
|
"// The GPU/offload knobs both compare loads must use",
|
|
)
|
|
assert "resetPromptQueue();" in failed_gpu_discovery
|
|
|
|
compare_run = _between(
|
|
send_flow,
|
|
"setComparing(true);",
|
|
"} else {",
|
|
)
|
|
failed_compare = _between(compare_run, "} catch (err) {", "} finally {")
|
|
assert "compareStepSucceededRef.current = false;" in failed_compare
|
|
assert "resetPromptQueue();" in failed_compare
|
|
|
|
|
|
def test_clear_all_invalidates_and_removes_late_fresh_thread_initialization():
|
|
target = _between(
|
|
THREAD,
|
|
"const createPromptQueueTarget = useCallback(",
|
|
"const dismissWaitToast",
|
|
)
|
|
assert "const historyClearGeneration = chatHistoryClearBoundary.capture()" in target
|
|
assert "chatHistoryClearBoundary.capture() !== historyClearGeneration" in target
|
|
assert "if (initializingFreshThread)" in target
|
|
assert "initializedFreshThreadId = remoteId" in target
|
|
assert "freshThreadAppendAccepted = true" in target
|
|
assert "removeFreshThreadPersistedAfterAbort()" in target
|
|
assert "removeFreshThreadPersistedAfterAbort(true)" not in target
|
|
assert "markChatThreadDeleted(initializedFreshThreadId)" in target
|
|
assert "deleteStoredChatThreads([initializedFreshThreadId])" in target
|
|
assert "aui.threads().switchToNewThread()" in target
|
|
assert "chatHistoryClearBoundary.advance();" in CLEAR_ALL_CHATS
|
|
assert CLEAR_ALL_CHATS.index("chatHistoryClearBoundary.advance();") < CLEAR_ALL_CHATS.index(
|
|
"requestPromptQueueStop();"
|
|
)
|
|
# Matched on the call prefix, not the whole call: #8932 gave clearStoredChats an options
|
|
# argument, which changes nothing about the ordering this pins.
|
|
assert CLEAR_ALL_CHATS.index("requestPromptQueueStop();") < CLEAR_ALL_CHATS.index(
|
|
"return await clearStoredChats("
|
|
)
|
|
assert "const historyClearGeneration = chatHistoryClearBoundary.capture();" in RUNTIME_PROVIDER
|
|
assert "await throwIfHistoryWasCleared(initialized.remoteId);" in RUNTIME_PROVIDER
|
|
assert "await throwIfHistoryWasCleared(remoteId);" in RUNTIME_PROVIDER
|
|
assert "trackStoredChatThreadRecord(" in RUNTIME_PROVIDER
|
|
assert "class ChatHistoryClearBoundary" in CHAT_CLEAR_BOUNDARY
|
|
assert "capture(): number" in CHAT_CLEAR_BOUNDARY
|
|
assert "advance(): number" in CHAT_CLEAR_BOUNDARY
|
|
assert "const reopenAdmission = threadRecordWrites.closeAdmission();" in CHAT_HISTORY_STORAGE
|
|
assert (
|
|
"const pendingThreadIds = threadRecordWrites.idsRequiringFence();" in CHAT_HISTORY_STORAGE
|
|
)
|
|
assert "tombstoneThreadIds: idsToFence" in CHAT_HISTORY_STORAGE
|
|
assert "threadRecordWrites.confirmFinalState(idsToFence);" in CHAT_HISTORY_STORAGE
|
|
|
|
|
|
def test_a_failed_thread_row_write_surfaces_to_the_patch_caller():
|
|
"""A retry that reports undefined reads as "no row to update", so the queued run's
|
|
model correction is dropped and never retried: thread.tsx clears
|
|
shouldCorrectPersistedModel right after the awaited updateStoredChatThread."""
|
|
retry = _between(
|
|
CHAT_HISTORY_STORAGE,
|
|
"async function retryFailedThreadRecord(",
|
|
"export async function listStoredChatMessages(",
|
|
)
|
|
# awaiting the tracked write, not the settle-all helper, is what propagates the failure
|
|
assert "await trackStoredChatThreadRecord(threadId, createRecord);" in retry
|
|
assert "await awaitStoredChatThreadWrites(threadId);\n return" not in retry
|
|
|
|
|
|
def test_noop_setting_refreshes_do_not_invalidate_pending_queues():
|
|
assert "shouldAdvanceQueuedSettingsEpoch(" in CHAT_RUNTIME_STORE
|
|
set_params = _between(CHAT_RUNTIME_STORE, "setParams: (params, options)", "setCustomPresets:")
|
|
assert "state.params," in set_params
|
|
assert "params," in set_params
|
|
assert "queuedSettingsChanged" in set_params
|
|
set_checkpoint = _between(
|
|
CHAT_RUNTIME_STORE,
|
|
"setCheckpoint: (modelId, ggufVariant, options)",
|
|
"setActiveThreadId:",
|
|
)
|
|
assert "nextGgufVariant" in set_checkpoint
|
|
assert "nextDeepResearchEnabled" in set_checkpoint
|
|
assert "queuedSettingsChanged" in set_checkpoint
|
|
|
|
|
|
def test_stop_delete_archive_and_clear_are_thread_scoped():
|
|
stop_listener = _between(
|
|
THREAD,
|
|
"window.addEventListener(PROMPT_QUEUE_STOP_EVENT",
|
|
"window.addEventListener(PROMPT_QUEUE_RUN_FAILED_EVENT",
|
|
)
|
|
assert "stopPromptQueueRunForThreadIds(threadIds)" in stop_listener
|
|
assert "requestPromptQueueStop(toArchive.map((thread) => thread.id));" in SIDEBAR_ITEMS
|
|
assert "requestPromptQueueStop(threadIds);" in SIDEBAR_ITEMS
|
|
assert "requestPromptQueueStop();" in CLEAR_ALL_CHATS
|
|
assert "serverCancelByThreadId" in CLEAR_ALL_CHATS
|
|
assert "stopChatThread(threadId)" in CLEAR_ALL_CHATS
|
|
assert "detail: { threadIds, temporaryOnly: true }" in QUEUE_BOUNDARY
|
|
assert "if (temporaryOnly)" in THREAD
|
|
assert "threadIds !== undefined && threadIds.length === 0" in QUEUE_BOUNDARY
|
|
assert "detail: threadIds ? { threadIds } : undefined" in QUEUE_BOUNDARY
|
|
assert "const aliasesByQueuedRun = new Map<string, string[]>()" in CONFIRM_MODEL_SWAP
|
|
assert "aliases.some((threadId) => runningIds.has(threadId))" in CONFIRM_MODEL_SWAP
|
|
|
|
|
|
def test_sidebar_exposes_queue_activity_for_each_thread():
|
|
assert "const queueByThreadId = usePromptQueueUI((s) => s.byThreadId);" in APP_SIDEBAR
|
|
assert "hasQueuedActivity" in APP_SIDEBAR
|
|
assert "showWorkSpinner" in APP_SIDEBAR
|
|
assert "{showWorkSpinner && (" in APP_SIDEBAR
|
|
assert "hasUnreadActivity" in APP_SIDEBAR
|
|
assert "clearChatNotifications(item)" in APP_SIDEBAR
|