Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/patch-kiro-canonical-session.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 42 additions & 1 deletion .github/workflows/engine-conformance-kiro.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions .github/workflows/shared/kiro.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ engine:
env:
KIRO_LOG_NO_COLOR: "1"
NO_COLOR: "1"
log-parser: |
function parseLog(logContent) {
return require("./parse_kiro_log.cjs").parseKiroLog(logContent);
}
mcp:
config-path: .kiro/settings/mcp.json
config-adapter: |
Expand Down Expand Up @@ -268,4 +272,25 @@ verification, process failures, and cleanup. These diagnostics do not print
API keys, MCP headers, configuration contents, or prompt contents. For Kiro's
own verbose CLI logging, add `--verbose` to `behaviors.execution.args` in this
shared definition when investigating a runtime failure.

The parser supports the older `> ` conversation layout and Kiro CLI 2.27's
`[tool]` announcements/statuses with buffered assistant answers. It writes
canonical `agent-session.jsonl`; conclusion projects that trace into
`usage/aw_session.jsonl`. The observed 200-byte command previews ending in `...`
are marked `inputTruncated: true`, not reconstructed as complete arguments.
Concurrent and orphan statuses
remain anonymous because stdout supplies no tool-call IDs. `Failed` is an
explicit tool failure; `Completed` establishes completion but does not supply
an exit code or independently verified success. Elapsed time, natural-language
claims, and credit summaries do not become token, USD, or turn accounting.

Sanitized regression excerpts in `actions/setup/js/fixtures/kiro_ci_sessions.cjs`
come from existing Smoke Kiro runs
[37862725262](https://github.com/github/gh-aw/actions/runs/37862725262) and
[37549851664](https://github.com/github/gh-aw/actions/runs/37549851664).
Both Kiro processes exited zero; the second workflow failed during log
redaction, not engine execution. The sampled stdout does not expose structured
user prompts, reasoning, provider refusals, tool outputs, or token usage.
Synthetic partial/error and canonical round-trip cases are labeled separately
and do not claim live coverage for those fields.
-->
43 changes: 42 additions & 1 deletion .github/workflows/smoke-kiro.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 21 additions & 5 deletions actions/setup/js/engine_log_parser.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -106,20 +106,36 @@ function normalizeEngineLogEntries(entries, engine) {

/** @param {string} content @param {string} engine @returns {any | undefined} */
function parseBehaviorLog(content, engine) {
if (engine === "kiro" && /^kiro-cli \d+\.\d+\.\d+/m.test(content) && /^\[(?:kiro-harness|tool)\]/m.test(content)) {
return require("./parse_kiro_log.cjs").parseKiroLog(content);
}
const parse = loadEngineLogParser(engine);
if (engine === "aider" && parse) {
const parsed = parse(content);
return { ...parsed, logEntries: normalizeEngineLogEntries(parsed?.logEntries ?? [], engine) };
}
if (engine === "crush" && parse) {
const parsed = parse(content);
// Older definitions relied on terminal extraction; canonical producers own framing.
if ((parsed?.logEntries ?? []).every(isSessionEvent)) {
return { ...parsed, logEntries: normalizeEngineLogEntries(parsed?.logEntries ?? [], engine) };
}
}
const records = require("./log_parser_shared.cjs").parseLogEntries(content) ?? [];
if (records.some(record => (isSessionEvent(record) && record.type !== "agent.execution") || (["assistant", "user"].includes(record?.type) && normalizeEngineLogEntries([record], engine).length > 0))) {
return { logEntries: normalizeEngineLogEntries(records, engine), mcpFailures: [], maxTurnsHit: false };
}
const parse = loadEngineLogParser(engine);
if (!parse) return undefined;
const lines = content.trimEnd().split("\n");
const lines = content.split("\n");
let terminalIndex = lines.length - 1;
while (terminalIndex >= 0 && !lines[terminalIndex].trim()) terminalIndex--;
let terminal;
if ((lines.at(-1) ?? "").trimStart().startsWith("{")) {
if ((lines[terminalIndex] ?? "").trimStart().startsWith("{")) {
try {
const record = JSON.parse(lines.at(-1) ?? "");
const record = JSON.parse(lines[terminalIndex] ?? "");
if (record.type === "result" && (Object.hasOwn(record, "num_turns") || Object.hasOwn(record, "usage"))) {
terminal = record;
lines.pop();
lines.splice(terminalIndex);
}
} catch {
const message = `${ERR_PARSE}: Malformed terminal JSON for ${engine}; retaining the original engine output`;
Expand Down
Loading
Loading