|
|
@@ -1,4 +1,4 @@
|
|
|
-import { Ripgrep } from "../file/ripgrep"
|
|
|
+import { Context, Effect, Layer } from "effect"
|
|
|
|
|
|
import { Instance } from "../project/instance"
|
|
|
|
|
|
@@ -33,44 +33,52 @@ export namespace SystemPrompt {
|
|
|
return [PROMPT_DEFAULT]
|
|
|
}
|
|
|
|
|
|
- export async function environment(model: Provider.Model) {
|
|
|
- const project = Instance.project
|
|
|
- return [
|
|
|
- [
|
|
|
- `You are powered by the model named ${model.api.id}. The exact model ID is ${model.providerID}/${model.api.id}`,
|
|
|
- `Here is some useful information about the environment you are running in:`,
|
|
|
- `<env>`,
|
|
|
- ` Working directory: ${Instance.directory}`,
|
|
|
- ` Workspace root folder: ${Instance.worktree}`,
|
|
|
- ` Is directory a git repo: ${project.vcs === "git" ? "yes" : "no"}`,
|
|
|
- ` 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 interface Interface {
|
|
|
+ readonly environment: (model: Provider.Model) => string[]
|
|
|
+ readonly skills: (agent: Agent.Info) => Effect.Effect<string | undefined>
|
|
|
}
|
|
|
|
|
|
- export async function skills(agent: Agent.Info) {
|
|
|
- if (Permission.disabled(["skill"], agent.permission).has("skill")) return
|
|
|
+ export class Service extends Context.Service<Service, Interface>()("@opencode/SystemPrompt") {}
|
|
|
|
|
|
- const list = await Skill.available(agent)
|
|
|
+ export const layer = Layer.effect(
|
|
|
+ Service,
|
|
|
+ Effect.gen(function* () {
|
|
|
+ const skill = yield* Skill.Service
|
|
|
|
|
|
- return [
|
|
|
- "Skills provide specialized instructions and workflows for specific tasks.",
|
|
|
- "Use the skill tool to load a skill when a task matches its description.",
|
|
|
- // the agents seem to ingest the information about skills a bit better if we present a more verbose
|
|
|
- // version of them here and a less verbose version in tool description, rather than vice versa.
|
|
|
- Skill.fmt(list, { verbose: true }),
|
|
|
- ].join("\n")
|
|
|
- }
|
|
|
+ return Service.of({
|
|
|
+ environment(model) {
|
|
|
+ const project = Instance.project
|
|
|
+ return [
|
|
|
+ [
|
|
|
+ `You are powered by the model named ${model.api.id}. The exact model ID is ${model.providerID}/${model.api.id}`,
|
|
|
+ `Here is some useful information about the environment you are running in:`,
|
|
|
+ `<env>`,
|
|
|
+ ` Working directory: ${Instance.directory}`,
|
|
|
+ ` Workspace root folder: ${Instance.worktree}`,
|
|
|
+ ` Is directory a git repo: ${project.vcs === "git" ? "yes" : "no"}`,
|
|
|
+ ` Platform: ${process.platform}`,
|
|
|
+ ` Today's date: ${new Date().toDateString()}`,
|
|
|
+ `</env>`,
|
|
|
+ ].join("\n"),
|
|
|
+ ]
|
|
|
+ },
|
|
|
+
|
|
|
+ skills: Effect.fn("SystemPrompt.skills")(function* (agent: Agent.Info) {
|
|
|
+ if (Permission.disabled(["skill"], agent.permission).has("skill")) return
|
|
|
+
|
|
|
+ const list = yield* skill.available(agent)
|
|
|
+
|
|
|
+ return [
|
|
|
+ "Skills provide specialized instructions and workflows for specific tasks.",
|
|
|
+ "Use the skill tool to load a skill when a task matches its description.",
|
|
|
+ // the agents seem to ingest the information about skills a bit better if we present a more verbose
|
|
|
+ // version of them here and a less verbose version in tool description, rather than vice versa.
|
|
|
+ Skill.fmt(list, { verbose: true }),
|
|
|
+ ].join("\n")
|
|
|
+ }),
|
|
|
+ })
|
|
|
+ }),
|
|
|
+ )
|
|
|
+
|
|
|
+ export const defaultLayer = layer.pipe(Layer.provide(Skill.defaultLayer))
|
|
|
}
|