Commit Graph

32648 Commits

Author SHA1 Message Date
kshitijk4poor
7b29f19146 refactor(constants): share the /proc reader between the cgroup and root-mount probes
_root_mount_has_marker duplicated _proc_file_has_marker's open/OSError shell;
both now go through _read_proc(), and the root-mount scan checks every "/"
line instead of returning on the first. The regression test exercises the
helper on both arms (host running containers -> False, containerd rootfs ->
True, missing file -> False) instead of patching builtins.open globally.
2026-09-08 02:27:24 +05:30
Bartok9
9160c4e27e fix(agent): scan only root mount in is_container() cgroup-v2 fallback
Closes #58135

On a cgroup-v2 host with Docker's containerd image store, is_container()
false-positives whenever any container is running. The mountinfo fallback
scanned the entire file for containerd/crio/kubepods substrings, but each
running container contributes an overlay mount whose option string carries
lowerdir=/var/lib/containerd/..., so a plain host was misclassified as a
container. The result is cached per-process, making it depend on whether a
container happened to be running at first call — which then flipped
subprocess HOME and broke browser tool launches (Chrome not found).

Fix: only inspect the root ('/') mount line. Inside a container the root
mount is the runtime's overlay/snapshot and carries the marker; on a host
the root is a real block device and container overlays live at non-root
mount points.

Adds a regression test reproducing the host-running-containers case.

(cherry picked from commit 588f55113ebc16813b8216772feb761b6292d922)
(cherry picked from commit f42295814d7e2b5fe681e6d1b96ea72026058195)
2026-09-08 02:27:24 +05:30
kshitijk4poor
ed063034ad test(compressor): pin custom_providers threading at the get_model_context_length seam
The previous test replaced _resolve_context_length itself with a fake that
re-did the threading, so it could not fail if the production call dropped the
kwarg; the sibling test only called get_model_context_length directly (green on
main, and its list-shaped `models` fixture is silently ignored by the config
loader). One test now patches agent.context_compressor.get_model_context_length
where production reads it and asserts the kwarg arrives; file moved next to the
other compressor tests. The defensive list copy is dropped (no caller mutates).
2026-09-08 02:27:01 +05:30
dhruv kejriwal
71516214c3 fix(compressor): thread custom_providers into context-length resolution
ContextCompressor._resolve_context_length called get_model_context_length
without custom_providers, so a per-model context_length override in
custom_providers (e.g. 256K for baseten-deepseek-flash) was skipped and the
hardcoded catalog default (128K for 'deepseek') won instead. /context then
reported the wrong window. Thread custom_providers through the compressor
constructor and into resolution.
2026-09-08 02:27:01 +05:30
kshitijk4poor
99e1c16868 test(tools): pin the Git Bash probe's detached stdin in the existing probe test
The new standalone test file duplicated TestGitBashExternalProgramProbe's
harness; one assertion on the recorded kwargs covers the #78820 contract.
The sibling ASLR-probe assertion is dropped (unchanged code, already green
on main). Comment trimmed to the WHY.
2026-09-08 02:26:39 +05:30
Shimakaze514
869432301b fix(tools): detach stdin in the Windows Git Bash probe (#78820)
`_bash_starts()` in tools/environments/local_gitbash_probe.py ran bash.exe
with capture_output=True but no stdin=, so the MSYS2 child inherited the
TUI gateway's stdin pipe. The MSYS2 runtime switches that shared pipe to
PIPE_NOWAIT; the gateway's next sys.stdin.readline() then fails with
ERROR_NO_DATA, which the CRT maps to OSError(EINVAL), and the gateway
exits with code 1 ("gateway exited") on the first terminal call.

The sibling probe _mandatory_aslr_enabled() already passes
stdin=subprocess.DEVNULL; this brings _bash_starts() in line with it.

Add tests/tools/test_gitbash_probe_stdin.py asserting both probes forward
stdin=DEVNULL to subprocess.run (fails on the pre-fix source).
2026-09-08 02:26:39 +05:30
kshitijk4poor
2e418f7a97 chore: map contributor email for Shimakaze514 2026-09-08 02:26:39 +05:30
kshitijk4poor
e5382cd823 test(qqbot): exercise the real dm session key in the existing approval-click test
The added test was a copy of test_approval_click_once_maps_to_once with only the
key's chat_type changed; retarget the original to the key build_source actually
emits. Both branches stay: approval keys carry "dm" (build_source), update-prompt
keys carry event.scene ("c2c") — a comment records why.
2026-09-08 02:26:31 +05:30
penginman
e0a6a43b2b test(qqbot): add approval auth test for dm session keys 2026-09-08 02:26:31 +05:30
penginman
2ff990c13f fix(qqbot): authorize approval clicks for dm session keys
PR #30737 added authorization checks for approval button clicks but
hardcoded chat_type == 'c2c'. C2C sessions are actually created with
chat_type='dm' (build_source at L1278, L1488), so the check always
rejects DM approval buttons as unauthorized.

Accept both 'c2c' and 'dm' for direct-message session keys.
2026-09-08 02:26:31 +05:30
kshitijk4poor
d6b3b6d9f6 chore: map contributor email for penginman 2026-09-08 02:26:31 +05:30
kshitijk4poor
1e24a8de39 refactor(delegation): resolve the child fallback chain through the canonical normalizer
_resolve_child_fallback_chain re-implemented hermes_cli.fallback_config's entry
validation to log per-index warnings, wrapped a pure function in try/except, and
carried two names (routing_cfg / fallback_cfg) for one argument. It now delegates
to get_fallback_chain() and keeps the single warning for "no usable routes";
the facade re-export is dropped (import from the defining module). Tests collapse
to the parametrized decision table plus the pin-derivation, real-config-loader,
review-ownership and activation invariants (22 -> 20 cases, 417 -> ~230 lines).
2026-09-08 02:26:05 +05:30
Ayush Nangia
c47bf78d68 fix(delegation): keep child routes and fallback policy together 2026-09-08 02:26:05 +05:30
Ayush Nangia
2f1085ec0b fix(delegation): reject malformed child fallback chains 2026-09-08 02:26:05 +05:30
Ayush Nangia
0a53094897 fix: key the pin on delegation.model as well (model arm of #80450)
A delegation.model-only pin (provider inherited) took the unpinned
column because pinned was keyed on override_provider alone, so the
child inherited the parent chain and a mid-run failure could silently
swap the pinned model. model at the call site is creds["model"] --
delegation.model config -- at both call sites, so keying on it adds no
false pins. base_url-only pins already resolve to a provider override.

Caught by review on the PR; two matrix tests added (model-only pin with
absent and declared chains).
2026-09-08 02:26:05 +05:30
Ayush Nangia
3204bfa5e2 docs+defaults: declare delegation.fallback_providers in config surfaces
Adopted from PR #80421 with the author's explicit go-ahead on #80450
('Please proceed!'): config_defaults entry, cli-config.yaml.example
block, and user-guide docs for the delegation-scoped fallback chain.

Co-authored-by: Andrex Ibiza, MBA <84248988+andrexibiza@users.noreply.github.com>
2026-09-08 02:26:05 +05:30
Ayush Nangia
72464503b4 fix(delegation): resolve the child fallback chain through the full pin x config matrix
Composes #80465's pin semantics with #80438/#80421's
delegation.fallback_providers semantics (#65038) and settles the
composition cell the three PRs leave undefined (#80450 map).

_resolve_child_fallback_chain implements the whole decision table in
one pure function: pinned children get no chain unless the delegation
section declares one (a delegation-scoped chain honors both explicit
intents; the silent drag in #80450 is specifically the PARENT chain
substituting a pin); an explicit empty list disables fallback; absent
config preserves historical parent inheritance exactly. Malformed
declared values log and fall back PIN-AWARE — never the parent chain on
a pinned child, so the config-error path cannot reintroduce the drag.
Entries normalize through the canonical get_fallback_chain.

The two existing inheritance tests are made hermetic against the real
user config (as #80438 also did).
2026-09-08 02:26:05 +05:30
Teknium
869228cab4 feat(delegation): surface process accounting as top-level process_notes in the sync result; add live stress harness
Stress run with a real orchestrator subagent showed the per-task keys buried in results[] were not relayed
upward; the same prose lines now sit at the top of the sync delegate_task result. evals/subagent_process_handoff/
stress_handoff_live.py runs 12 real parent+child scenarios (handoff, orphan, unread, clean read, cap, exited refusal,
mixed fan-out, parent controlling the inherited process, sibling theft incl. adversarial, nested orchestrator,
5-way burst) and scores them against runtime accounting, never model prose.
2026-09-07 12:50:29 -07:00
Teknium
ef9239571d feat(delegation): report a child's exited-but-unread notify processes to the parent
A process that finishes while the child is alive needs no handoff, but if the child never
polls/waits/logs it, the result vanished: the completion notice is suppressed in the parent
and the child's summary never mentions it. Finalization now attaches exit code + output
tail as unread_completions, rendered in the parent's delegation notice.
2026-09-07 12:50:29 -07:00
Teknium
b2c394bcad test: derive process_manage verbs from the handler table; widen aux-cancellation start-up bound
The schema-diet test froze the verb list (a change-detector); it now asserts the enum
matches _SESSION_ACTIONS plus the by-name verbs. The cancellation harness gave a worker
thread 1 s to reach its transport, which a loaded CI runner missed twice this week; the
cancellation-latency assertion is unchanged, only the start-up wait is wider.
2026-09-07 12:50:29 -07:00
Teknium
3c0d90e8ef feat(delegation): subagents hand background processes to the parent; leftovers are named, not trusted
A child's background processes are killed at its teardown and their
notify_on_complete notices are suppressed in the parent, yet the child's
terminal result still said `notify_on_complete: true` and the parent's
delegation notice said nothing about processes left behind. Orchestrators
believed "CI watcher running" and waited on a completion that could never
arrive (recurring in the Sep 7 campaign sessions).

- process_manage(action="handoff", session_id, data="<purpose>"), children
  only: process_registry.transfer_ownership flips owner_task_id/task_id/
  session_key to the parent under the registry lock, so the completion is
  stamped with the parent's owner at exit, passes the parent's sa- filter,
  and is reaped by the parent, not the child. Cap 3 per child; an exited,
  foreign, or non-child request is a tool error. The purpose rides the
  event as handoff_note and renders in the parent's notice.
- Child terminal(background=True, notify=True) now returns
  notify_on_complete=false plus a note: wait, kill, or hand off.
- _ChildRun.account_background_processes records handed_off_processes and
  orphaned_processes on the result before cleanup kills the leftovers; the
  parent's delegation block renders both.
2026-09-07 12:50:29 -07:00
Teknium
03f3b09222 fix(tui-gateway): subagent lifecycle survives display.tool_progress=off
`_on_tool_progress` bailed on the tool-progress gate before dispatching
`subagent.*`, so a Desktop/TUI user who hid tool-call chrome also lost the
subagent rows in the status stack and spawn tree. Subagent lifecycle is
application state (like `todo.updated`, clarify and MCP consent cards,
which already bypass the gate); the gate now applies only to the optional
progress chrome (reasoning previews, MoA rows, tool.generating).
2026-09-07 11:25:20 -07:00
Teknium
610c869ac6 fix(desktop): task panel follows the todo_list wire name
The core-tool rename shipped `todo_list` on the wire (legacy alias `todo`
kept for old transcripts), but the Desktop renderer still matched the tool
by the literal `todo` in seven places: the live tool.start/tool.complete
mirror into the composer status stack, the todo-stream router, args
carry-over, the transcript hoist, the silent-tool class, the count noun,
and stored-history hydration. Every live task update therefore went into
the transcript as an ordinary tool row while the task panel stayed empty,
and reopening a chat never restored a finished list.

One predicate (`isTodoToolName`) now owns the wire/legacy name pair and
every site reads it.
2026-09-07 11:25:20 -07:00
kshitijk4poor
e9bccc90a5 refactor: repoint 10 MessageEvent/MessageType importers that landed on main after the event.py split
Five test files and five evals scripts merged since this branch's base still import the
moved names via gateway.platforms.base. They work (base.py imports the names for its own
use) but the PR's invariant is that in-tree code imports from the defining module.
2026-09-07 22:47:33 +05:30
kshitijk4poor
284b303fa8 test: e2e conftest imports GatewayRunner at module level; elicitation test docstring matches the default thunk
Same cleanup as the previous commit, applied to the third file that carried the
TYPE_CHECKING + in-function import pair. gateway.run imports none of the telegram/discord/
slack modules the conftest stubs, so import order is not a concern. test_feishu.py keeps its
TYPE_CHECKING import on purpose (FeishuAdapter is gated on optional lark_oapi).
2026-09-07 22:47:33 +05:30
kshitijk4poor
c54de79459 test: /btw replies HISTORY_UNREADABLE on a failed transcript read (from #102952)
Regression guard for the one-line import fix in commit 1; identical to the test in #102952,
whose /btw half is superseded by this PR. Red on origin/main (NameError), green here.
2026-09-07 22:47:33 +05:30
kshitijk4poor
2f1609a86c refactor: sms AIOHTTP_AVAILABLE flag; ElicitationHandler call_context defaults to a no-op thunk; drop stale TYPE_CHECKING/type-ignore in two tests
Self-review follow-ups on the F821 sweep:

- plugins/platforms/sms/adapter.py: the optional-import block now sets AIOHTTP_AVAILABLE like
  the homeassistant / webhook / whatsapp_cloud adapters, and both call sites test the flag.
  Removes the `if not aiohttp is not None:` double negation left by inlining
  `_aiohttp_available()`.
- tools/mcp_tool_sampling.py: `call_context` defaults to `lambda: None` so the use site is a
  single call instead of an Optional guard; the only None caller was a test. The
  `from __future__ import annotations` was noise (`Context` is a runtime import). Comment
  names the actual cycle (mcp_tool_server_run imports this module).
- gateway/platforms/helpers.py: drop the `from __future__ import annotations` — the only
  MessageEvent annotations are attribute-target locals, which are never evaluated.
- tests/gateway/test_telegram_audio_vs_voice.py, test_video_context_note.py: module-level
  `from gateway.run import GatewayRunner` like the ~100 sibling files; the
  TYPE_CHECKING block + `# type: ignore[name-defined]` were contradicting each other.
  (tests/e2e/conftest.py and test_feishu.py keep TYPE_CHECKING deliberately: they stub
  telegram/discord before importing, and FeishuAdapter is gated on optional lark_oapi.)

Mutation check: neutralising the thunk read (`captured = None`) fails
test_captured_context_is_replayed_in_consent_call; restored → 14/14 green. ty on the three
touched production files vs origin/main: 0 new, 6 resolved.
2026-09-07 22:47:33 +05:30
kshitijk4poor
ab2f4602de refactor: MessageEvent to gateway/platforms/event.py; ElicitationHandler takes a call_context thunk
Breaks the two import cycles that forced Protocol stand-ins in the F821 sweep, so the two
sites now name the real types.

gateway/platforms/event.py (new leaf): MessageType, ProcessingOutcome, MessageEvent moved
out of base.py verbatim. Their only dependency is gateway.session.SessionSource; base.py
imported helpers.py at module level, so helpers could not name MessageEvent. Now
TextBatchAggregator is typed by the real MessageEvent. 249 importers repointed
(`from gateway.platforms.base import` -> `.event`, preserving each import's layout);
gateway.platforms.__init__ re-exports from .event. The three revert-scheduled PLUGIN-COMPAT
pointers that named these symbols (gateway.slash_commands → MessageType, dingtalk → MessageType,
photon → ProcessingOutcome) and their COMPAT_MANIFEST rows now target gateway.platforms.event.
Docs updated: ADDING_A_PLATFORM.md, adding-platform-adapters.md (en + zh-Hans).

tools/mcp_tool_sampling.py: ElicitationHandler no longer holds a back-reference to its
MCPServerTask (mcp_tool imports sampling, so the task type cannot be named there). It only
ever read owner._pending_call_context, so it takes `call_context: Callable[[], Context | None]`
and MCPServerTask passes `lambda: self._pending_call_context`. The consent call is one
`functools.partial`, run directly or inside the captured Context.

ty on the 11 touched production files vs origin/main: 0 new diagnostics, 14 resolved.
(The one `source: SessionSource = None` diagnostic moves with the class; typing it Optional
exposes ~60 unguarded call sites — separate follow-up.)

Tests: tests/gateway + tests/plugins + tests/tools + touched files, 18,235 passed; the 31
failures reproduce identically on origin/main (macOS /private/tmp, systemd socket,
long-path fixtures, live-service tests).
2026-09-07 22:47:33 +05:30
kshitijk4poor
c5ff900761 fix: resolve the 33 F821 undefined names outside tui_gateway / feishu / godmode
Sweep of `ruff check . --select F821 --target-version py311`: 2,234 hits. 2,201 are left
alone on purpose: tui_gateway (2,169; bind_module rebinds bodies onto server.py globals,
all names verified to resolve there), the Feishu adapter (27; globals().update() SDK
binding) and the godmode script (5; dead standalone script). The other 33 were all
genuine defects. No lint config change; no TYPE_CHECKING escape hatches — every
annotation names a real, imported type; ty on the touched files: 0 new diagnostics.

- gateway/slash_commands.py: HISTORY_UNREADABLE never imported after #102117
  → NameError on the /btw error branch (same one-liner as #102952).
- gateway/platforms/whatsapp_common.py: `-> Path` return annotation with no Path
  import (the body uses `_Path`). Never raised at runtime thanks to
  `from __future__ import annotations`, but `typing.get_type_hints()` and ty
  both fail on it.
- gateway/run.py: ActivityProvenance imported at module level
  (agent.session_activity has no gateway deps); stringly annotation and the
  lazy in-function import are gone.
- tools/patch_parser.py: PatchResult imported at module level; real return
  annotation. The "avoid circular import" lazy import guarded a cycle that
  does not exist (file_operations_common never imports patch_parser).
- gateway/platforms/helpers.py: base.py imports helpers at module level, so
  MessageEvent cannot be named here; TextBatchAggregator only reads .text and
  .source, so it is typed by a BatchableEvent Protocol that MessageEvent
  satisfies structurally.
- tools/mcp_tool_sampling.py: mcp_tool imports this module, so MCPServerTask
  cannot be named here; ElicitationHandler only reads
  owner._pending_call_context, typed by an ElicitationOwner Protocol.
- plugins/platforms/sms/adapter.py: aiohttp is an optional dep ([messaging] extra) →
  module-level try/except ImportError binding `aiohttp = web = None`, the pattern the
  homeassistant / webhook / whatsapp_cloud adapters already use. Retires three lazy
  in-function imports and the `_aiohttp_available()` wrapper; `_handle_webhook` typed
  `web.Request -> web.Response`.
- plugins/platforms/teams/summary_writer.py: plain module-level `import httpx` — httpx is a
  hard core dependency (pyproject `httpx[socks]==0.28.1`), so the lazy import and the
  "imported on every CLI start" docstring premise were both wrong (plugin discovery never
  imports this module; it is reached only via the Teams adapter / meeting pipeline).

Tests:
- tests/hermes_cli/test_config.py: a test body orphaned by the wave-1 prune
  (6b81590c55) sat inside the class as dead code with self/tmp_path unbound
  — header restored, so the v11→12 custom_providers migration is covered.
- tests/tools/test_mcp_tool.py: @staticmethod recursing on `self` in the
  win32 branch; call portalocker directly.
- tests/test_background_review_list_shapes.py: main() still ran 3 pruned tests.
- tests/agent/test_cursor_optimizations_parity.py: bench() used names only
  imported inside a sibling test.
- GatewayRunner / FeishuAdapter / Dict / Optional: missing imports.
2026-09-07 22:47:33 +05:30
kshitijk4poor
233757037d test(openai): Astra pricing/capability tests assert contracts, not snapshots
``amount_usd == Decimal("5.450025")`` and ``pricing_version == "openai-gpt-6-astra-2026-09"``
fail on the next price or version bump without catching a bug. The whole-request tier is the
contract: above 272K prompt tokens every component — including cache writes, the field this PR
adds — is billed at its ``*_above`` rate, so derive the expected total from the entry's own rates
and assert below < above. Likewise the builtin-metadata test keeps only what
``_UNKNOWN_MODEL_BASE`` could not have supplied (vision) plus the openai-api == openai parity.
2026-09-07 21:43:54 +05:30
kshitijk4poor
f850bc58ed refactor(inventory): build the gated-Astra warning tail instead of string-replacing a sentence
`warning.replace("Showing the saved model only.", ...)` silently no-ops the day that sentence is
reworded. Pick the tail sentence first, format once.
2026-09-07 21:43:54 +05:30
kshitijk4poor
e583d68c14 perf(models): stop revalidating a fresh provider cache just because it lists Astra
``gated_cache`` bypassed both the fresh-hit and the stale-while-revalidate branches of
``cached_provider_model_ids`` whenever the disk entry contained Astra. For an entitled
account that is every entry: live discovery rewrites the entry with Astra → next call is gated
again → a blocking /models round-trip on every picker open, for exactly the providers the user
is most likely on. The parallel prefetch's staleness check didn't know about the gate either, so
it skipped the slug and the blocking call landed in the serial picker loop the prefetch exists to
avoid.

Gate on provenance, not contents: only live discovery ever writes Astra into a same-credential
entry (the static/offline paths filter it out), so a fresh entry IS the entitlement record. The
one filter that matters stays — a stale entry served because the refresh failed drops Astra, and
the entry itself is left intact so the next successful fetch restores it.

The regression test now pins both halves: fresh entry served with Astra and zero live calls;
failed refresh past the fresh window serves the entry minus Astra.
2026-09-07 21:43:54 +05:30
kshitijk4poor
b6852995ed refactor(openai): one is_astra_model predicate; gate Astra at the untrusted Codex inputs
The slug pair {"gpt-6-astra", "gpt-6-astra-900k"} was spelled out five times
(reasoning_effort, transports/codex, models.py x2, codex_models) with five hand-rolled
``.strip().lower().rsplit("/", 1)[-1]`` normalisations. ``is_astra_model`` in
agent/reasoning_effort.py (the module the other four already import) is now the only home, so a
new Astra alias is one edit.

``_finalize_codex_models(..., allow_astra=)`` was a control-coupling flag set True by the two
live callers and left False by the two static ones. The filter now lives where the untrusted
inputs are — ``_drop_undiscovered_astra`` over config.toml default + models_cache.json in
``get_codex_model_ids`` — and ``_finalize_codex_models`` is back to its one-line original.
DEFAULT_CODEX_MODELS never contains Astra, so the static catalog needs no gate.

``_openai_catalog`` appends whatever Astra ids live discovery returned instead of a name-keyed
``if "gpt-6-astra" in live_lower`` branch with a literal fallback that could never fire.
2026-09-07 21:43:54 +05:30
kshitijk4poor
170a73637d fix(openai): drop prompt_cache_options from Astra requests — not an SDK kwarg, 30m is the server default
Every direct-API (api.openai.com) Astra request raised
``TypeError: Responses.create() got an unexpected keyword argument 'prompt_cache_options'``
before reaching the network: openai 2.24.0's Responses.create has no such parameter and no
**kwargs, and neither send path relocates it into extra_body. The PR's tests stopped at
build_kwargs/preflight so the SDK boundary was never crossed.

OpenAI's prompt-caching guide states ``prompt_cache_options.ttl`` accepts only ``30m`` and that
``30m`` is the default, so the field carried no information: sending nothing yields the same
cache lifetime. The sanitizer now only removes what the API rejects (none/minimal effort,
sampling/logprob knobs, the pre-5.6 ``prompt_cache_retention``) and never adds a field, which
also keeps the request body byte-stable for the cache prefix.

Also: none/minimal→low no longer needs a bespoke {"", "none", "disabled", "off"} set —
``clamp_effort`` against CODEX_ASTRA_EFFORTS already resolves to the floor (``low``); and the
auxiliary adapter derives ``is_codex_backend`` from ``classify_responses_route`` (the declared
single owner of that predicate) instead of re-implementing the host test inline.

Tests reshaped to contracts: the two proxy/subdomain cases collapse into one parametrised
"exact host only" test asserting effort and temperature pass through untouched.
2026-09-07 21:43:54 +05:30
Eva
fdb76ce643 fix(openai): include canonical API picker identity in Astra discovery gate
(cherry picked from commit de57e601193a955a69201e1a274d5ccab83a7634)
2026-09-07 21:43:54 +05:30
Eva
328542d807 fix(openai): revalidate Astra at cached and saved-model picker boundaries
(cherry picked from commit f46e2f4c0609c1543d5636c780c6da0d5ce09a56)
2026-09-07 21:43:54 +05:30
Eva
299d86851c fix(openai): keep Astra 900K alias gated and wire-compatible
(cherry picked from commit c7cd27d7f050598b9dc052c73fa1dc78c045d3c6)
2026-09-07 21:43:54 +05:30
Michael Steuer
17c7be1485 feat(models): preserve live-verified Astra 900K opt-in from #103132
Retain the two context-variant metadata additions by Michael Steuer. Keep the dedicated Astra reasoning contract already present in #103057 rather than replacing it with the GPT-5.6 vocabulary.

(cherry picked from commit add3a4fa6f31ea3f5fdad701a840d4f8530eb30e)
(cherry picked from commit 1672f12c260260ea38ed636528c02aee734d62b1)
2026-09-07 21:43:54 +05:30
Eva
3825d25191 fix(openai): cap Astra Codex OAuth fallback
(cherry picked from commit bb4156c3881cbaf20736f0fcfd6c3cc5c861a6fb)
2026-09-07 21:43:54 +05:30
Eva
850680fcdf fix(openai): require canonical host for Astra cache
(cherry picked from commit 6e73cc5cc66e4003276c4472e6ce2d77e602f130)
2026-09-07 21:43:54 +05:30
Eva
5a82258626 fix(openai): keep Astra rules on eligible routes
(cherry picked from commit f92fb9d9964e6e8ea118035c548aae812054f504)
2026-09-07 21:43:54 +05:30
Eva
c990017482 test(openai): close Astra baseline review gaps
(cherry picked from commit 8c27b7c9316ba675e4d9ebcc7a659754f37f18ef)
2026-09-07 21:43:54 +05:30
Eva
2c315ff59b feat(openai): add GPT-6 Astra baseline support
(cherry picked from commit a8c53d20c6b16cc35745e364e16bb7259166a1d3)
2026-09-07 21:43:54 +05:30
Teknium
a7198a8855 fix: keep budget checkpoints out of cancelled tool results
Skip checkpoint evaluation when a turn is interrupted so cancellation rows
remain durable without urging continued execution. The existing minimal-agent
interrupt regression also avoids dereferencing an absent iteration budget.

Consolidate the warning coverage into two invariants, including real SQLite
readback and dispatcher/child scope controls. Cold-start tool availability
between construction cases to model independent worker processes. Place ratio
normalization beside the existing iteration budget instead of growing init.

Real cancelled-tool A/B against current main, draft, and fix: three cancelled
rows and zero writes on all arms; persisted checkpoint notices 0 / 1 / 0.
Repeated scripted HTTP/SQLite loop A/B preserves completion opportunity,
ordinary default-off behavior, and blocked/two-failure exhaustion behavior.

Local targeted run initially passed 15 cases with one fixture cache-isolation
failure; corrected target and inherited affected suites remain queued behind
the campaign lock. This commit is not a CI-green or merge-ready claim.
2026-09-07 08:28:43 -07:00
Teknium
35104c20f5 test: pin checkpoint transcript persistence before the next request 2026-09-07 08:28:43 -07:00
Teknium
93af3db01d fix: checkpoint Kanban completion before tool access expires
Give dispatcher-owned workers a tool-capable reporting opportunity before the
hard iteration cap, without accepting arbitrary diffs or weakening failure
counting. Add opt-in per-turn iteration checkpoints for ordinary agents.
Persist checkpoint text with the fresh tool result, never rewrite cached rows.

Salvages the opt-in ratio and per-turn reset implementation from #104683;
credits the earlier default-off signpost proposal in #92438.

Local fixture wire A/B: Kanban ready/1 failure -> done/0; deliberately stuck
workers still reach blocked/2 after two runs. Default-off control unchanged.
Targeted and affected-directory suites queued behind campaign test lock.

Co-authored-by: fangliquanflq <fangliquan@qq.com>
Co-authored-by: C. Michael Gibbs <252231331+MikeGibbsOnyx@users.noreply.github.com>
2026-09-07 08:28:43 -07:00
Teknium
ff175510c2 test(cron): preserve rejected creation exit status 2026-09-07 08:27:50 -07:00
Teknium
39ed610f8c feat(cron): create paused jobs without a scheduling race
Persist paused state, timestamp, reason and no first trigger in the original
locked creation write. Forward the same boolean contract across CLI, tool,
gateway API and dashboard API, validating at the store boundary. Preserve
explicit operator force-run behavior and normal enabled creation.

The live CLI probe also caught the command shim dropping failure return codes;
forward them so invalid creation reports exit 1 rather than success.

Credit earlier atomic-creation work in #78935 and #94952 and the focused
implementation in #104578. The broader manifest staging layer is not imported.

Co-authored-by: Konstantin Khlopkov <konstantin.khlopkov93@gmail.com>
Co-authored-by: Chloé DuPont <321112755+misschloedupont@users.noreply.github.com>
2026-09-07 08:27:50 -07:00
Teknium
7f80efc294 fix(tui): post-turn completion drain resolves ownership once; barrier test uses a watch
Rebasing onto main surfaced three reds in tests/test_tui_gateway_server.py.

Two were a real double-check: _run_post_turn_followups already drains the
completion queue through _session_owns_notification_event, then handed the
events to _notif_handle_ready, which re-ran the belongs-elsewhere and
requires-owner gates on every event — a second compression-lineage DB
lookup per notification for events the caller had just proven ours.
_notif_handle_ready/_notif_handle_event take an explicit owned=True from
the post-turn path and skip only the ownership gates (consumed/dedup/turn
claiming still run). The poller path is unchanged (owned defaults False).

The third, test_run_prompt_submit_requeues_all_unstarted_notifications_with_real_threading,
asserted that three consecutive completions produce one in-flight turn plus
two requeued events; under this PR's contract (#104671) consecutive
completions share one turn, so the first event is now a watch_match — the
documented turn barrier — and the test keeps proving that the two
completions behind an in-flight notification turn are never lost.

A/B: revert the tui_gateway hunks and the two lineage tests fail with
ownership_checks recorded twice; restore and all 11 test_run_prompt_submit
tests pass.
2026-09-07 08:27:07 -07:00
Teknium
ada8e50f2d test: verify completion barriers and document local delivery proof 2026-09-07 08:27:07 -07:00