test_llm_judge_validates_compiled_workflow fails: the judge returns
pass=false, reporting structural items from the kitchen-sink agent spec
as missing from the compiled workflowDef.
Listed as a plain reason string rather than run:false — the test makes a
single judge call and fails fast, so there is no CI time to reclaim, and
leaving it running means a fix surfaces as XPASS.
E2E_MIN_PASSED drops 135 -> 134 in the same commit, as the known-failures
README requires: an added entry moves a test out of the PASSED column, and
without the matching decrement the lane fails on the passed-count floor
for an unrelated-looking reason.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mkdocs.yml declares the mermaid custom fence as
`!!python/name:main.mermaid_fence`, which PyYAML resolves with a plain
`import main` while parsing the config. The deploy action runs the mkdocs
console script inside a Docker container, where sys.path[0] is the script's
bin directory rather than the checkout, so the import fails and the deploy
aborts before building.
Point PYTHONPATH at the container's workspace mount so main.py resolves.
Run 32411004435 failed with:
cannot find module 'main' (No module named 'main')
in "/github/workspace/mkdocs.yml", line 283, column 19
* fix: propagate CANCELED instead of FAILED from JOIN when a forked branch is canceled
* test: cover permissive fork join sub workflows terminated by the user in the test harness
---------
Co-authored-by: Naomi Most <naomi.most@orkes.io>
* - Add end to end integration tests
- Update playwright so it can get OPENAI_API_KEY from .env.local
* Bump coverage percentage to 90% to test CI before merging in additional tests
* Update workflow to use coverage report script
* Add tests and remove kitchen
* - Delete orphaned components
- Cleanup local coverage runs
* Make test less flaky
* Run integration tests in docker for consistent snapshots
* Show incompletion reasons
---------
Co-authored-by: Dale Brady <49766562+bradyyie@users.noreply.github.com>
- Extract shared buildContextInjectionTask/injectContextIntoUserMessage on
AgentCompiler and reuse across both compilers (3 duplicated sites); the
swarm loop now honors the configured context size limits instead of
hardcoded defaults, and the user-message rewrite uses a ListIterator
instead of index bookkeeping.
- Extract parentHandsOffOnToolOf predicate for the swarm turn-skip check.
- Join: move the agent output-shaping explanation onto prepareAgentOutput's
javadoc and return unmodifiable maps for the constructed shapes
(LinkedHashMap kept over Map.of — tool outputs may contain nulls; the
pass-through branch stays live to preserve default JOIN behavior).
agentspan:
- Only suppress an agent's post-tool-call turn when a parent on_tool_result
handoff actually watches a tool that agent owns, instead of suppressing it
for every sub-agent in the swarm whenever any handoff targets any tool.
Otherwise a sub-agent's own tool result was never summarized in words
because its loop ended before the LLM saw the output.
- Add a ctx_inject task to the resumed per-turn loop so a turn that does
keep looping (per the above fix) can see prior state/tool-results instead
of just the bare prompt, mirroring AgentCompiler's existing wiring.
ui-next:
- Guard AgentExecutionDiagram's response sublabel against undefined text so
a tool-call-only turn renders an empty sublabel instead of the literal
string "undefined".
- In agentExecutionUtils, render handoffs (explicit transfer, condition-based
via handoff_check, or HANDOFF-strategy routing) for real sub-agent turns,
which previously showed nothing between agents handing off work.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The End Time column on the executions and task search pages is marked
sortable, and the date-range picker emits `endTime>`/`endTime<` clauses.
`end_time` was never a column on workflow_index or task_index, so the
query builders snake_cased the field, failed to match it against
VALID_FIELDS, and dropped it -- from the ORDER BY via getSort() and from
the WHERE via Condition.isValid(). Sorting by End Time returned an
unordered page and lost the default `startTime:DESC`; filtering by an
End Time range silently returned unfiltered results.
Add end_time to both index tables on sqlite and postgres, index it,
populate it from the summary on write, and add it to the allow-list.
The millis-to-UTC conversion applied to filter values keys off the
`_time` suffix, so the date range needs no further change.
The column is NOT NULL defaulting to the epoch rather than nullable.
End time is absent until an execution is terminal, and SQLite sorts
NULL lowest while Postgres sorts it highest, so a nullable column would
put still-running executions at opposite ends of an endTime:DESC page
depending on the backend. getSort() emits a bare
`attribute + " " + order` with no room for a NULLS clause, so the
sentinel is what keeps the two engines agreeing: unfinished rows carry
the epoch and sort last on DESC, first on ASC, on both. This follows the
update_time sentinel already in V1 and V13.1.
end_time is added to the ON CONFLICT update clause as well as the
insert, since the row already exists by the time a workflow finishes.
Existing rows are back-filled from json_data, which already holds the
instant as an ISO-8601 string. Terminal executions are never re-indexed,
so without a back-fill every historical execution would sort as
unfinished forever.
Both back-fills are written to survive a malformed value rather than
abort. Sqlite's strftime() returns NULL on one and COALESCE keeps the
epoch. Postgres needs more care than V13.2 took: to_timestamp with a
fixed 'YYYY-MM-DD"T"HH24:MI:SS.MS' raises `invalid value "Z" for "MS"`
on an endTime with no milliseconds, and since applyDataMigrations
defaults to true that would abort the migration and stop the server
booting. V18.1 uses a ::timestamptz cast, which accepts any ISO-8601
form and reads the trailing Z as UTC, behind a regex guard so a
non-timestamp value skips the row instead of failing the statement.
Verified on a 3913-workflow / 45531-task sqlite database: all 3822
finished workflows match json_data exactly with 0 mismatches, the 91
unfinished rows keep the epoch, and `ORDER BY end_time DESC` plans as
`SCAN workflow_index USING INDEX workflow_index_end_time_idx`. On
postgres, V18 then V18.1 against seeded data converts values with and
without milliseconds and with offsets, and leaves empty, malformed and
absent endTimes at the epoch.
No UI change: only `workflowType` was ever remapped on the way out, so
`endTime` already reached the server unchanged.