Compare commits

...

4 Commits

Author SHA1 Message Date
Kit Langton
876b96bc76 Merge branch 'dev' into worktree-agent-a5489f0a 2026-04-10 23:51:39 -04:00
Kit Langton
d1e1cba45b Merge branch 'dev' into worktree-agent-a5489f0a 2026-04-10 23:42:29 -04:00
Kit Langton
b0ccf0486d refactor(session): convert SystemPrompt facade calls to effectful versions
Replace `Effect.promise(() => SystemPrompt.skills(...))` and
`Effect.promise(() => SystemPrompt.environment(...))` with direct
effectful calls. `environment` is now a plain sync function (the async
Ripgrep.tree call was dead code behind `&& false`). `skills` is now an
`Effect.fn` that takes the Skill service as a parameter.
2026-04-10 23:41:14 -04:00
Kit Langton
30edf5aa42 refactor(session): convert SystemPrompt facade calls to effectful versions
Replace `Effect.promise(() => SystemPrompt.skills(...))` and
`Effect.promise(() => SystemPrompt.environment(...))` with direct
effectful calls. `environment` is now a plain sync function (the async
Ripgrep.tree call was dead code behind `&& false`). `skills` is now an
`Effect.fn` that takes the Skill service as a parameter.
2026-04-10 23:40:14 -04:00
5 changed files with 24 additions and 22 deletions

View File

@@ -48,6 +48,7 @@ import { EffectLogger } from "@/effect/logger"
import { InstanceState } from "@/effect/instance-state"
import { makeRuntime } from "@/effect/run-service"
import { TaskTool, type TaskPromptOps } from "@/tool/task"
import { Skill } from "@/skill"
import { SessionRunState } from "./run-state"
// @ts-ignore
@@ -102,6 +103,7 @@ export namespace SessionPrompt {
const instruction = yield* Instruction.Service
const state = yield* SessionRunState.Service
const revert = yield* SessionRevert.Service
const skill = yield* Skill.Service
const run = {
promise: <A, E>(effect: Effect.Effect<A, E>) =>
@@ -1462,8 +1464,8 @@ NOTE: At any point in time through this workflow you should feel free to ask the
yield* plugin.trigger("experimental.chat.messages.transform", {}, { messages: msgs })
const [skills, env, instructions, modelMsgs] = yield* Effect.all([
Effect.promise(() => SystemPrompt.skills(agent)),
Effect.promise(() => SystemPrompt.environment(model)),
SystemPrompt.skills(agent, skill),
Effect.sync(() => SystemPrompt.environment(model)),
instruction.system().pipe(Effect.orDie),
MessageV2.toModelMessagesEffect(msgs, model),
])
@@ -1687,9 +1689,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
Layer.provide(Plugin.defaultLayer),
Layer.provide(Session.defaultLayer),
Layer.provide(SessionRevert.defaultLayer),
Layer.provide(Agent.defaultLayer),
Layer.provide(Bus.layer),
Layer.provide(CrossSpawnSpawner.defaultLayer),
Layer.provide(Layer.mergeAll(Agent.defaultLayer, Skill.defaultLayer, Bus.layer, CrossSpawnSpawner.defaultLayer)),
),
)
const { runPromise } = makeRuntime(Service, defaultLayer)

View File

@@ -1,4 +1,4 @@
import { Ripgrep } from "../file/ripgrep"
import { Context, Effect } from "effect"
import { Instance } from "../project/instance"
@@ -33,7 +33,7 @@ export namespace SystemPrompt {
return [PROMPT_DEFAULT]
}
export async function environment(model: Provider.Model) {
export function environment(model: Provider.Model) {
const project = Instance.project
return [
[
@@ -46,24 +46,17 @@ export namespace SystemPrompt {
` Platform: ${process.platform}`,
` Today's date: ${new Date().toDateString()}`,
`</env>`,
`<directories>`,
` ${
project.vcs === "git" && false
? await Ripgrep.tree({
cwd: Instance.directory,
limit: 50,
})
: ""
}`,
`</directories>`,
].join("\n"),
]
}
export async function skills(agent: Agent.Info) {
export const skills = Effect.fn("SystemPrompt.skills")(function* (
agent: Agent.Info,
skill: Context.Service.Shape<typeof Skill.Service>,
) {
if (Permission.disabled(["skill"], agent.permission).has("skill")) return
const list = await Skill.available(agent)
const list = yield* skill.available(agent)
return [
"Skills provide specialized instructions and workflows for specific tasks.",
@@ -72,5 +65,5 @@ export namespace SystemPrompt {
// version of them here and a less verbose version in tool description, rather than vice versa.
Skill.fmt(list, { verbose: true }),
].join("\n")
}
})
}

View File

@@ -193,6 +193,7 @@ function makeHttp() {
Layer.provideMerge(registry),
Layer.provideMerge(trunc),
Layer.provide(Instruction.defaultLayer),
Layer.provide(Skill.defaultLayer),
Layer.provideMerge(deps),
),
)

View File

@@ -157,6 +157,7 @@ function makeHttp() {
Layer.provideMerge(registry),
Layer.provideMerge(trunc),
Layer.provide(Instruction.defaultLayer),
Layer.provide(Skill.defaultLayer),
Layer.provideMerge(deps),
),
)

View File

@@ -1,7 +1,9 @@
import { describe, expect, test } from "bun:test"
import path from "path"
import { Effect } from "effect"
import { Agent } from "../../src/agent/agent"
import { Instance } from "../../src/project/instance"
import { Skill } from "../../src/skill"
import { SystemPrompt } from "../../src/session/system"
import { tmpdir } from "../fixture/fixture"
@@ -38,8 +40,13 @@ description: ${description}
directory: tmp.path,
fn: async () => {
const build = await Agent.get("build")
const first = await SystemPrompt.skills(build!)
const second = await SystemPrompt.skills(build!)
const runSkills = Effect.gen(function* () {
const svc = yield* Skill.Service
return yield* SystemPrompt.skills(build!, svc)
}).pipe(Effect.provide(Skill.defaultLayer))
const first = await Effect.runPromise(runSkills)
const second = await Effect.runPromise(runSkills)
expect(first).toBe(second)