mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-12 21:02:17 +02:00
feat(x/core): turn runtime with event-sourced execution loop (stage 2)
The TurnRuntime per turn-runtime-design.md: constructor-injected, container-ignorant, no per-turn state — every advanceTurn reconstructs from the JSONL log, so normal execution and crash recovery share one path. - runtime.ts: createTurn/advanceTurn/getTurn; durable-barrier appends before side effects; sequential sync tools with progress; async tool exposure + durable suspension; permission pipeline (checker → optional classifier batch → human/deny fallback, fail-closed on checker errors); cancellation with synthetic results; recovery that re-issues interrupted model calls and continues after interrupted sync tools; model-call-limit exhaustion with machine-readable code. - fs-repo.ts: date-partitioned append-only JSONL, strict line validation, path-traversal rejection, per-turn in-process locking. - stream.ts: hot execution stream — buffers before the consumer attaches, outcome independent of consumption, close-drops-events. - context-resolver.ts: chain-walking materialization of context references with cycle detection. - Seam interfaces for stage-4 bridges: model/tool registries, permission checker/classifier, agent resolver, lifecycle bus, clock. - shared reducer: track classification failures durably so failed classifications are never re-run. 67 new tests: all nine §26 end-to-end scenarios (mocked deps, recovery boundaries seeded directly) plus repo/stream/resolver suites. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
d821c419fe
commit
cda17c2d40
21 changed files with 3656 additions and 1 deletions
|
|
@ -506,6 +506,7 @@ describe("tool execution", () => {
|
|||
permResolved("tc1", "deny", "human"),
|
||||
result("tc1", "echo", "runtime", "Permission denied", true),
|
||||
]);
|
||||
expect(state.toolCalls[0].permission?.classificationFailed).toBe(true);
|
||||
expect(state.toolCalls[0].result?.result.isError).toBe(true);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -382,6 +382,9 @@ export interface ToolCallState {
|
|||
permission?: {
|
||||
required: z.infer<typeof ToolPermissionRequired>;
|
||||
classification?: z.infer<typeof ToolPermissionClassified>;
|
||||
// Set when a tool_permission_classification_failed event named this
|
||||
// call; such calls are treated as defer and never re-classified.
|
||||
classificationFailed?: boolean;
|
||||
resolved?: z.infer<typeof ToolPermissionResolved>;
|
||||
};
|
||||
invocation?: z.infer<typeof ToolInvocationRequested>;
|
||||
|
|
@ -635,8 +638,8 @@ function applyToolPermissionClassificationFailed(
|
|||
if (toolCall.permission.resolved) {
|
||||
fail(`classification failure after permission resolution: ${toolCallId}`);
|
||||
}
|
||||
toolCall.permission.classificationFailed = true;
|
||||
}
|
||||
// Recorded for the audit trail; does not currently affect derived state.
|
||||
}
|
||||
|
||||
function applyToolPermissionResolved(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue