feat(core): make path-local instruction discovery durable
Replace synthetic-message instruction injection with a durable discovery projection so discovered AGENTS.md files survive compaction, forks, reverts, and restarts. - Add the instruction_file table and the durable session.instructions.discovered event; projection stores each discovered path and content with its owning assistant-message boundary and durable discovery order. - Fold discovered files into the core/instructions source through InstructionDiscovery, absorbing SessionInstructions. Completed compaction rebaselines restate discovered instructions instead of summarizing them away. - Re-read discovered files live at each observation so mid-session edits reach the model; the frozen discovery content stands in only when a file becomes unreadable. - Narrate instruction file changes as per-file deltas via diffByKey, restating the full set only for pure reorderings. - Fork copies discoveries within the inherited transcript, committed revert removes discoveries past the revert boundary, and Session movement clears them so the destination initializes a complete baseline.
This commit is contained in:
parent
754dd57177
commit
0726f09b05
28 changed files with 1166 additions and 598 deletions
|
|
@ -73,8 +73,10 @@ const model = OpenAIChat.route
|
|||
})
|
||||
.model({ id: "gpt-4o-mini" })
|
||||
const models = SessionRunnerModel.layerWith(() => Effect.succeed(SessionRunnerModel.resolved(model)))
|
||||
const systemContext = Layer.mock(InstructionBuiltIns.Service, { load: () => Effect.succeed(Instructions.empty) })
|
||||
const instructionContext = Layer.mock(InstructionDiscovery.Service, { load: () => Effect.succeed(Instructions.empty) })
|
||||
const instructionBuiltIns = Layer.mock(InstructionBuiltIns.Service, { load: () => Effect.succeed(Instructions.empty) })
|
||||
const instructionDiscovery = Layer.mock(InstructionDiscovery.Service, {
|
||||
load: (_sessionID) => Effect.succeed(Instructions.empty),
|
||||
})
|
||||
const skillGuidance = Layer.mock(SkillGuidance.Service, { load: () => Effect.succeed(Instructions.empty) })
|
||||
const referenceGuidance = Layer.mock(ReferenceGuidance.Service, { load: () => Effect.succeed(Instructions.empty) })
|
||||
const mcpGuidance = Layer.mock(McpGuidance.Service, { load: () => Effect.succeed(Instructions.empty) })
|
||||
|
|
@ -83,8 +85,8 @@ const runnerLayer = AppNodeBuilder.build(SessionRunnerLLM.node, [
|
|||
[Snapshot.node, Snapshot.noopLayer],
|
||||
[LayerNodePlatform.llmClient, client],
|
||||
[SessionRunnerModel.node, models],
|
||||
[InstructionBuiltIns.node, systemContext],
|
||||
[InstructionDiscovery.node, instructionContext],
|
||||
[InstructionBuiltIns.node, instructionBuiltIns],
|
||||
[InstructionDiscovery.node, instructionDiscovery],
|
||||
[Location.node, Location.boundNode({ directory: AbsolutePath.make("/project") })],
|
||||
[SkillGuidance.node, skillGuidance],
|
||||
[ReferenceGuidance.node, referenceGuidance],
|
||||
|
|
@ -133,8 +135,8 @@ const it = testEffect(
|
|||
[PermissionV2.node, permission],
|
||||
[ToolOutputStore.node, ToolOutputStore.nodeWithoutConfig],
|
||||
[SessionRunnerModel.node, models],
|
||||
[InstructionBuiltIns.node, systemContext],
|
||||
[InstructionDiscovery.node, instructionContext],
|
||||
[InstructionBuiltIns.node, instructionBuiltIns],
|
||||
[InstructionDiscovery.node, instructionDiscovery],
|
||||
[Location.node, Location.boundNode({ directory: AbsolutePath.make("/project") })],
|
||||
[SkillGuidance.node, skillGuidance],
|
||||
[ReferenceGuidance.node, referenceGuidance],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue