refactor(effect): align permission and truncate entrypoints
This commit is contained in:
parent
52df7b8927
commit
ba26993361
28 changed files with 86 additions and 83 deletions
|
|
@ -5,7 +5,7 @@ import { ModelID, ProviderID } from "../provider/schema"
|
||||||
import { generateObject, streamObject, type ModelMessage } from "ai"
|
import { generateObject, streamObject, type ModelMessage } from "ai"
|
||||||
import { SystemPrompt } from "../session/system"
|
import { SystemPrompt } from "../session/system"
|
||||||
import { Instance } from "../project/instance"
|
import { Instance } from "../project/instance"
|
||||||
import { Truncate } from "../tool/truncation"
|
import { Truncate } from "../tool/truncate"
|
||||||
import { Auth } from "../auth"
|
import { Auth } from "../auth"
|
||||||
import { ProviderTransform } from "../provider/transform"
|
import { ProviderTransform } from "../provider/transform"
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ import PROMPT_COMPACTION from "./prompt/compaction.txt"
|
||||||
import PROMPT_EXPLORE from "./prompt/explore.txt"
|
import PROMPT_EXPLORE from "./prompt/explore.txt"
|
||||||
import PROMPT_SUMMARY from "./prompt/summary.txt"
|
import PROMPT_SUMMARY from "./prompt/summary.txt"
|
||||||
import PROMPT_TITLE from "./prompt/title.txt"
|
import PROMPT_TITLE from "./prompt/title.txt"
|
||||||
import { PermissionNext } from "@/permission/next"
|
import { PermissionNext } from "@/permission"
|
||||||
import { mergeDeep, pipe, sortBy, values } from "remeda"
|
import { mergeDeep, pipe, sortBy, values } from "remeda"
|
||||||
import { Global } from "@/global"
|
import { Global } from "@/global"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import type { MessageV2 } from "../../../session/message-v2"
|
||||||
import { MessageID, PartID } from "../../../session/schema"
|
import { MessageID, PartID } from "../../../session/schema"
|
||||||
import { ToolRegistry } from "../../../tool/registry"
|
import { ToolRegistry } from "../../../tool/registry"
|
||||||
import { Instance } from "../../../project/instance"
|
import { Instance } from "../../../project/instance"
|
||||||
import { PermissionNext } from "../../../permission/next"
|
import { PermissionNext } from "../../../permission"
|
||||||
import { iife } from "../../../util/iife"
|
import { iife } from "../../../util/iife"
|
||||||
import { bootstrap } from "../../bootstrap"
|
import { bootstrap } from "../../bootstrap"
|
||||||
import { cmd } from "../cmd"
|
import { cmd } from "../cmd"
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import { createOpencodeClient, type Message, type OpencodeClient, type ToolPart
|
||||||
import { Server } from "../../server/server"
|
import { Server } from "../../server/server"
|
||||||
import { Provider } from "../../provider/provider"
|
import { Provider } from "../../provider/provider"
|
||||||
import { Agent } from "../../agent/agent"
|
import { Agent } from "../../agent/agent"
|
||||||
import { PermissionNext } from "../../permission/next"
|
import { PermissionNext } from "../../permission"
|
||||||
import { Tool } from "../../tool/tool"
|
import { Tool } from "../../tool/tool"
|
||||||
import { GlobTool } from "../../tool/glob"
|
import { GlobTool } from "../../tool/glob"
|
||||||
import { GrepTool } from "../../tool/grep"
|
import { GrepTool } from "../../tool/grep"
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,15 @@ import { AccountService } from "@/account/service"
|
||||||
import { AuthService } from "@/auth/service"
|
import { AuthService } from "@/auth/service"
|
||||||
import { Instances } from "@/effect/instances"
|
import { Instances } from "@/effect/instances"
|
||||||
import type { InstanceServices } from "@/effect/instances"
|
import type { InstanceServices } from "@/effect/instances"
|
||||||
import { TruncateService } from "@/tool/truncate-service"
|
import { TruncateEffect } from "@/tool/truncate-effect"
|
||||||
import { Instance } from "@/project/instance"
|
import { Instance } from "@/project/instance"
|
||||||
|
|
||||||
export const runtime = ManagedRuntime.make(
|
export const runtime = ManagedRuntime.make(
|
||||||
Layer.mergeAll(AccountService.defaultLayer, Instances.layer, TruncateService.layer).pipe(
|
Layer.mergeAll(
|
||||||
Layer.provideMerge(AuthService.defaultLayer),
|
AccountService.defaultLayer, //
|
||||||
),
|
TruncateEffect.defaultLayer,
|
||||||
|
Instances.layer,
|
||||||
|
).pipe(Layer.provideMerge(AuthService.defaultLayer)),
|
||||||
)
|
)
|
||||||
|
|
||||||
export function runPromiseInstance<A, E>(effect: Effect.Effect<A, E, InstanceServices>) {
|
export function runPromiseInstance<A, E>(effect: Effect.Effect<A, E, InstanceServices>) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Hono } from "hono"
|
import { Hono } from "hono"
|
||||||
import { describeRoute, validator, resolver } from "hono-openapi"
|
import { describeRoute, validator, resolver } from "hono-openapi"
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
import { PermissionNext } from "@/permission/next"
|
import { PermissionNext } from "@/permission"
|
||||||
import { PermissionID } from "@/permission/schema"
|
import { PermissionID } from "@/permission/schema"
|
||||||
import { errors } from "../error"
|
import { errors } from "../error"
|
||||||
import { lazy } from "../../util/lazy"
|
import { lazy } from "../../util/lazy"
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import { Todo } from "../../session/todo"
|
||||||
import { Agent } from "../../agent/agent"
|
import { Agent } from "../../agent/agent"
|
||||||
import { Snapshot } from "@/snapshot"
|
import { Snapshot } from "@/snapshot"
|
||||||
import { Log } from "../../util/log"
|
import { Log } from "../../util/log"
|
||||||
import { PermissionNext } from "@/permission/next"
|
import { PermissionNext } from "@/permission"
|
||||||
import { PermissionID } from "@/permission/schema"
|
import { PermissionID } from "@/permission/schema"
|
||||||
import { ModelID, ProviderID } from "@/provider/schema"
|
import { ModelID, ProviderID } from "@/provider/schema"
|
||||||
import { errors } from "../error"
|
import { errors } from "../error"
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import { SessionID, MessageID, PartID } from "./schema"
|
||||||
|
|
||||||
import type { Provider } from "@/provider/provider"
|
import type { Provider } from "@/provider/provider"
|
||||||
import { ModelID, ProviderID } from "@/provider/schema"
|
import { ModelID, ProviderID } from "@/provider/schema"
|
||||||
import { PermissionNext } from "@/permission/next"
|
import { PermissionNext } from "@/permission"
|
||||||
import { Global } from "@/global"
|
import { Global } from "@/global"
|
||||||
import type { LanguageModelV2Usage } from "@ai-sdk/provider"
|
import type { LanguageModelV2Usage } from "@ai-sdk/provider"
|
||||||
import { iife } from "@/util/iife"
|
import { iife } from "@/util/iife"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import type { MessageV2 } from "./message-v2"
|
||||||
import { Plugin } from "@/plugin"
|
import { Plugin } from "@/plugin"
|
||||||
import { SystemPrompt } from "./system"
|
import { SystemPrompt } from "./system"
|
||||||
import { Flag } from "@/flag/flag"
|
import { Flag } from "@/flag/flag"
|
||||||
import { PermissionNext } from "@/permission/next"
|
import { PermissionNext } from "@/permission"
|
||||||
import { Auth } from "@/auth"
|
import { Auth } from "@/auth"
|
||||||
|
|
||||||
export namespace LLM {
|
export namespace LLM {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import type { Provider } from "@/provider/provider"
|
||||||
import { LLM } from "./llm"
|
import { LLM } from "./llm"
|
||||||
import { Config } from "@/config/config"
|
import { Config } from "@/config/config"
|
||||||
import { SessionCompaction } from "./compaction"
|
import { SessionCompaction } from "./compaction"
|
||||||
import { PermissionNext } from "@/permission/next"
|
import { PermissionNext } from "@/permission"
|
||||||
import { Question } from "@/question"
|
import { Question } from "@/question"
|
||||||
import { PartID } from "./schema"
|
import { PartID } from "./schema"
|
||||||
import type { SessionID, MessageID } from "./schema"
|
import type { SessionID, MessageID } from "./schema"
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,12 @@ import { fn } from "@/util/fn"
|
||||||
import { SessionProcessor } from "./processor"
|
import { SessionProcessor } from "./processor"
|
||||||
import { TaskTool } from "@/tool/task"
|
import { TaskTool } from "@/tool/task"
|
||||||
import { Tool } from "@/tool/tool"
|
import { Tool } from "@/tool/tool"
|
||||||
import { PermissionNext } from "@/permission/next"
|
import { PermissionNext } from "@/permission"
|
||||||
import { SessionStatus } from "./status"
|
import { SessionStatus } from "./status"
|
||||||
import { LLM } from "./llm"
|
import { LLM } from "./llm"
|
||||||
import { iife } from "@/util/iife"
|
import { iife } from "@/util/iife"
|
||||||
import { Shell } from "@/shell/shell"
|
import { Shell } from "@/shell/shell"
|
||||||
import { Truncate } from "@/tool/truncation"
|
import { Truncate } from "@/tool/truncate"
|
||||||
import { decodeDataUrl } from "@/util/data-url"
|
import { decodeDataUrl } from "@/util/data-url"
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { sqliteTable, text, integer, index, primaryKey } from "drizzle-orm/sqlit
|
||||||
import { ProjectTable } from "../project/project.sql"
|
import { ProjectTable } from "../project/project.sql"
|
||||||
import type { MessageV2 } from "./message-v2"
|
import type { MessageV2 } from "./message-v2"
|
||||||
import type { Snapshot } from "../snapshot"
|
import type { Snapshot } from "../snapshot"
|
||||||
import type { PermissionNext } from "../permission/next"
|
import type { PermissionNext } from "../permission"
|
||||||
import type { ProjectID } from "../project/schema"
|
import type { ProjectID } from "../project/schema"
|
||||||
import type { SessionID, MessageID, PartID } from "./schema"
|
import type { SessionID, MessageID, PartID } from "./schema"
|
||||||
import type { WorkspaceID } from "../control-plane/schema"
|
import type { WorkspaceID } from "../control-plane/schema"
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import PROMPT_CODEX from "./prompt/codex_header.txt"
|
||||||
import PROMPT_TRINITY from "./prompt/trinity.txt"
|
import PROMPT_TRINITY from "./prompt/trinity.txt"
|
||||||
import type { Provider } from "@/provider/provider"
|
import type { Provider } from "@/provider/provider"
|
||||||
import type { Agent } from "@/agent/agent"
|
import type { Agent } from "@/agent/agent"
|
||||||
import { PermissionNext } from "@/permission/next"
|
import { PermissionNext } from "@/permission"
|
||||||
import { Skill } from "@/skill"
|
import { Skill } from "@/skill"
|
||||||
|
|
||||||
export namespace SystemPrompt {
|
export namespace SystemPrompt {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import { DiscoveryService } from "./discovery"
|
||||||
import { Glob } from "../util/glob"
|
import { Glob } from "../util/glob"
|
||||||
import { pathToFileURL } from "url"
|
import { pathToFileURL } from "url"
|
||||||
import type { Agent } from "@/agent/agent"
|
import type { Agent } from "@/agent/agent"
|
||||||
import { PermissionNext } from "@/permission/next"
|
import { PermissionNext } from "@/permission"
|
||||||
import { InstanceContext } from "@/effect/instance-context"
|
import { InstanceContext } from "@/effect/instance-context"
|
||||||
import { Effect, Layer, ServiceMap } from "effect"
|
import { Effect, Layer, ServiceMap } from "effect"
|
||||||
import { runPromiseInstance } from "@/effect/runtime"
|
import { runPromiseInstance } from "@/effect/runtime"
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import { Flag } from "@/flag/flag.ts"
|
||||||
import { Shell } from "@/shell/shell"
|
import { Shell } from "@/shell/shell"
|
||||||
|
|
||||||
import { BashArity } from "@/permission/arity"
|
import { BashArity } from "@/permission/arity"
|
||||||
import { Truncate } from "./truncation"
|
import { Truncate } from "./truncate"
|
||||||
import { Plugin } from "@/plugin"
|
import { Plugin } from "@/plugin"
|
||||||
|
|
||||||
const MAX_METADATA_LENGTH = 30_000
|
const MAX_METADATA_LENGTH = 30_000
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import { CodeSearchTool } from "./codesearch"
|
||||||
import { Flag } from "@/flag/flag"
|
import { Flag } from "@/flag/flag"
|
||||||
import { Log } from "@/util/log"
|
import { Log } from "@/util/log"
|
||||||
import { LspTool } from "./lsp"
|
import { LspTool } from "./lsp"
|
||||||
import { Truncate } from "./truncation"
|
import { Truncate } from "./truncate"
|
||||||
|
|
||||||
import { ApplyPatchTool } from "./apply_patch"
|
import { ApplyPatchTool } from "./apply_patch"
|
||||||
import { Glob } from "../util/glob"
|
import { Glob } from "../util/glob"
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import { SessionPrompt } from "../session/prompt"
|
||||||
import { iife } from "@/util/iife"
|
import { iife } from "@/util/iife"
|
||||||
import { defer } from "@/util/defer"
|
import { defer } from "@/util/defer"
|
||||||
import { Config } from "../config/config"
|
import { Config } from "../config/config"
|
||||||
import { PermissionNext } from "@/permission/next"
|
import { PermissionNext } from "@/permission"
|
||||||
|
|
||||||
const parameters = z.object({
|
const parameters = z.object({
|
||||||
description: z.string().describe("A short (3-5 words) description of the task"),
|
description: z.string().describe("A short (3-5 words) description of the task"),
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
import type { MessageV2 } from "../session/message-v2"
|
import type { MessageV2 } from "../session/message-v2"
|
||||||
import type { Agent } from "../agent/agent"
|
import type { Agent } from "../agent/agent"
|
||||||
import type { PermissionNext } from "../permission/next"
|
import type { PermissionNext } from "../permission"
|
||||||
import type { SessionID, MessageID } from "../session/schema"
|
import type { SessionID, MessageID } from "../session/schema"
|
||||||
import { Truncate } from "./truncation"
|
import { Truncate } from "./truncate"
|
||||||
|
|
||||||
export namespace Tool {
|
export namespace Tool {
|
||||||
interface Metadata {
|
interface Metadata {
|
||||||
|
|
|
||||||
|
|
@ -1,62 +1,64 @@
|
||||||
import path from "path"
|
|
||||||
import { Log } from "../util/log"
|
|
||||||
import { TRUNCATION_DIR } from "./truncation-dir"
|
|
||||||
import { Identifier } from "../id/id"
|
|
||||||
import type { Agent } from "../agent/agent"
|
|
||||||
import { PermissionService } from "../permission/service"
|
|
||||||
import { NodeFileSystem, NodePath } from "@effect/platform-node"
|
import { NodeFileSystem, NodePath } from "@effect/platform-node"
|
||||||
import { Cause, Duration, Effect, FileSystem, Layer, Schedule, ServiceMap } from "effect"
|
import { Cause, Duration, Effect, FileSystem, Layer, Schedule, ServiceMap } from "effect"
|
||||||
|
import path from "path"
|
||||||
|
import type { Agent } from "../agent/agent"
|
||||||
|
import { PermissionService } from "../permission/service"
|
||||||
|
import { Identifier } from "../id/id"
|
||||||
|
import { Log } from "../util/log"
|
||||||
import { ToolID } from "./schema"
|
import { ToolID } from "./schema"
|
||||||
|
import { TRUNCATION_DIR } from "./truncation-dir"
|
||||||
|
|
||||||
const log = Log.create({ service: "truncation" })
|
export namespace TruncateEffect {
|
||||||
const RETENTION = Duration.days(7)
|
const log = Log.create({ service: "truncation" })
|
||||||
|
const RETENTION = Duration.days(7)
|
||||||
|
|
||||||
export const MAX_LINES = 2000
|
export const MAX_LINES = 2000
|
||||||
export const MAX_BYTES = 50 * 1024
|
export const MAX_BYTES = 50 * 1024
|
||||||
|
export const DIR = TRUNCATION_DIR
|
||||||
|
export const GLOB = path.join(TRUNCATION_DIR, "*")
|
||||||
|
|
||||||
export type Result = { content: string; truncated: false } | { content: string; truncated: true; outputPath: string }
|
export type Result = { content: string; truncated: false } | { content: string; truncated: true; outputPath: string }
|
||||||
|
|
||||||
export interface Options {
|
export interface Options {
|
||||||
maxLines?: number
|
maxLines?: number
|
||||||
maxBytes?: number
|
maxBytes?: number
|
||||||
direction?: "head" | "tail"
|
direction?: "head" | "tail"
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasTaskTool(agent?: Agent.Info) {
|
function hasTaskTool(agent?: Agent.Info) {
|
||||||
if (!agent?.permission) return false
|
if (!agent?.permission) return false
|
||||||
return PermissionService.evaluate("task", "*", agent.permission).action !== "deny"
|
return PermissionService.evaluate("task", "*", agent.permission).action !== "deny"
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace TruncateService {
|
export interface Api {
|
||||||
export interface Service {
|
|
||||||
readonly cleanup: () => Effect.Effect<void>
|
readonly cleanup: () => Effect.Effect<void>
|
||||||
readonly output: (text: string, options?: Options, agent?: Agent.Info) => Effect.Effect<Result>
|
readonly output: (text: string, options?: Options, agent?: Agent.Info) => Effect.Effect<Result>
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export class TruncateService extends ServiceMap.Service<TruncateService, TruncateService.Service>()(
|
export class Service extends ServiceMap.Service<Service, Api>()("@opencode/Truncate") {}
|
||||||
"@opencode/Truncate",
|
|
||||||
) {
|
export const layer = Layer.effect(
|
||||||
static readonly layer = Layer.effect(
|
Service,
|
||||||
TruncateService,
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const fs = yield* FileSystem.FileSystem
|
const fs = yield* FileSystem.FileSystem
|
||||||
|
|
||||||
const cleanup = Effect.fn("TruncateService.cleanup")(function* () {
|
const cleanup = Effect.fn("TruncateEffect.cleanup")(function* () {
|
||||||
const cutoff = Identifier.timestamp(Identifier.create("tool", false, Date.now() - Duration.toMillis(RETENTION)))
|
const cutoff = Identifier.timestamp(Identifier.create("tool", false, Date.now() - Duration.toMillis(RETENTION)))
|
||||||
const entries = yield* fs
|
const entries = yield* fs.readDirectory(TRUNCATION_DIR).pipe(
|
||||||
.readDirectory(TRUNCATION_DIR)
|
Effect.map((all) => all.filter((name) => name.startsWith("tool_"))),
|
||||||
.pipe(
|
Effect.catch(() => Effect.succeed([])),
|
||||||
Effect.map((all) => all.filter((name) => name.startsWith("tool_"))),
|
)
|
||||||
Effect.catch(() => Effect.succeed([])),
|
|
||||||
)
|
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
if (Identifier.timestamp(entry) >= cutoff) continue
|
if (Identifier.timestamp(entry) >= cutoff) continue
|
||||||
yield* fs.remove(path.join(TRUNCATION_DIR, entry)).pipe(Effect.catch(() => Effect.void))
|
yield* fs.remove(path.join(TRUNCATION_DIR, entry)).pipe(Effect.catch(() => Effect.void))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const output = Effect.fn("TruncateService.output")(function* (text: string, options: Options = {}, agent?: Agent.Info) {
|
const output = Effect.fn("TruncateEffect.output")(function* (
|
||||||
|
text: string,
|
||||||
|
options: Options = {},
|
||||||
|
agent?: Agent.Info,
|
||||||
|
) {
|
||||||
const maxLines = options.maxLines ?? MAX_LINES
|
const maxLines = options.maxLines ?? MAX_LINES
|
||||||
const maxBytes = options.maxBytes ?? MAX_BYTES
|
const maxBytes = options.maxBytes ?? MAX_BYTES
|
||||||
const direction = options.direction ?? "head"
|
const direction = options.direction ?? "head"
|
||||||
|
|
@ -116,7 +118,6 @@ export class TruncateService extends ServiceMap.Service<TruncateService, Truncat
|
||||||
} as const
|
} as const
|
||||||
})
|
})
|
||||||
|
|
||||||
// Start delayed hourly cleanup — scoped to runtime lifetime
|
|
||||||
yield* cleanup().pipe(
|
yield* cleanup().pipe(
|
||||||
Effect.catchCause((cause) => {
|
Effect.catchCause((cause) => {
|
||||||
log.error("truncation cleanup failed", { cause: Cause.pretty(cause) })
|
log.error("truncation cleanup failed", { cause: Cause.pretty(cause) })
|
||||||
|
|
@ -127,7 +128,9 @@ export class TruncateService extends ServiceMap.Service<TruncateService, Truncat
|
||||||
Effect.forkScoped,
|
Effect.forkScoped,
|
||||||
)
|
)
|
||||||
|
|
||||||
return TruncateService.of({ cleanup, output })
|
return Service.of({ cleanup, output })
|
||||||
}),
|
}),
|
||||||
).pipe(Layer.provide(NodeFileSystem.layer), Layer.provide(NodePath.layer))
|
)
|
||||||
|
|
||||||
|
export const defaultLayer = layer.pipe(Layer.provide(NodeFileSystem.layer), Layer.provide(NodePath.layer))
|
||||||
}
|
}
|
||||||
|
|
@ -1,21 +1,19 @@
|
||||||
import path from "path"
|
|
||||||
import { TRUNCATION_DIR } from "./truncation-dir"
|
|
||||||
import type { Agent } from "../agent/agent"
|
import type { Agent } from "../agent/agent"
|
||||||
import { runtime } from "@/effect/runtime"
|
import { runtime } from "@/effect/runtime"
|
||||||
import * as S from "./truncate-service"
|
import { TruncateEffect as S } from "./truncate-effect"
|
||||||
|
|
||||||
|
|
||||||
export namespace Truncate {
|
export namespace Truncate {
|
||||||
export const MAX_LINES = S.MAX_LINES
|
export const MAX_LINES = S.MAX_LINES
|
||||||
export const MAX_BYTES = S.MAX_BYTES
|
export const MAX_BYTES = S.MAX_BYTES
|
||||||
export const DIR = TRUNCATION_DIR
|
export const DIR = S.DIR
|
||||||
export const GLOB = path.join(TRUNCATION_DIR, "*")
|
export const GLOB = S.GLOB
|
||||||
|
|
||||||
export type Result = S.Result
|
export type Result = S.Result
|
||||||
|
|
||||||
export type Options = S.Options
|
export type Options = S.Options
|
||||||
|
|
||||||
export async function output(text: string, options: Options = {}, agent?: Agent.Info): Promise<Result> {
|
export async function output(text: string, options: Options = {}, agent?: Agent.Info): Promise<Result> {
|
||||||
return runtime.runPromise(S.TruncateService.use((s) => s.output(text, options, agent)))
|
return runtime.runPromise(S.Service.use((s) => s.output(text, options, agent)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,7 +3,7 @@ import path from "path"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { tmpdir } from "../fixture/fixture"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { Agent } from "../../src/agent/agent"
|
import { Agent } from "../../src/agent/agent"
|
||||||
import { PermissionNext } from "../../src/permission/next"
|
import { PermissionNext } from "../../src/permission"
|
||||||
|
|
||||||
// Helper to evaluate permission for a tool with wildcard pattern
|
// Helper to evaluate permission for a tool with wildcard pattern
|
||||||
function evalPerm(agent: Agent.Info | undefined, permission: string): PermissionNext.Action | undefined {
|
function evalPerm(agent: Agent.Info | undefined, permission: string): PermissionNext.Action | undefined {
|
||||||
|
|
@ -76,7 +76,7 @@ test("explore agent denies edit and write", async () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test("explore agent asks for external directories and allows Truncate.GLOB", async () => {
|
test("explore agent asks for external directories and allows Truncate.GLOB", async () => {
|
||||||
const { Truncate } = await import("../../src/tool/truncation")
|
const { Truncate } = await import("../../src/tool/truncate")
|
||||||
await using tmp = await tmpdir()
|
await using tmp = await tmpdir()
|
||||||
await Instance.provide({
|
await Instance.provide({
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
|
|
@ -463,7 +463,7 @@ test("legacy tools config maps write/edit/patch/multiedit to edit permission", a
|
||||||
})
|
})
|
||||||
|
|
||||||
test("Truncate.GLOB is allowed even when user denies external_directory globally", async () => {
|
test("Truncate.GLOB is allowed even when user denies external_directory globally", async () => {
|
||||||
const { Truncate } = await import("../../src/tool/truncation")
|
const { Truncate } = await import("../../src/tool/truncate")
|
||||||
await using tmp = await tmpdir({
|
await using tmp = await tmpdir({
|
||||||
config: {
|
config: {
|
||||||
permission: {
|
permission: {
|
||||||
|
|
@ -483,7 +483,7 @@ test("Truncate.GLOB is allowed even when user denies external_directory globally
|
||||||
})
|
})
|
||||||
|
|
||||||
test("Truncate.GLOB is allowed even when user denies external_directory per-agent", async () => {
|
test("Truncate.GLOB is allowed even when user denies external_directory per-agent", async () => {
|
||||||
const { Truncate } = await import("../../src/tool/truncation")
|
const { Truncate } = await import("../../src/tool/truncate")
|
||||||
await using tmp = await tmpdir({
|
await using tmp = await tmpdir({
|
||||||
config: {
|
config: {
|
||||||
agent: {
|
agent: {
|
||||||
|
|
@ -507,7 +507,7 @@ test("Truncate.GLOB is allowed even when user denies external_directory per-agen
|
||||||
})
|
})
|
||||||
|
|
||||||
test("explicit Truncate.GLOB deny is respected", async () => {
|
test("explicit Truncate.GLOB deny is respected", async () => {
|
||||||
const { Truncate } = await import("../../src/tool/truncation")
|
const { Truncate } = await import("../../src/tool/truncate")
|
||||||
await using tmp = await tmpdir({
|
await using tmp = await tmpdir({
|
||||||
config: {
|
config: {
|
||||||
permission: {
|
permission: {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { describe, test, expect } from "bun:test"
|
import { describe, test, expect } from "bun:test"
|
||||||
import { PermissionNext } from "../src/permission/next"
|
import { PermissionNext } from "../src/permission"
|
||||||
import { Config } from "../src/config/config"
|
import { Config } from "../src/config/config"
|
||||||
import { Instance } from "../src/project/instance"
|
import { Instance } from "../src/project/instance"
|
||||||
import { tmpdir } from "./fixture/fixture"
|
import { tmpdir } from "./fixture/fixture"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { Effect } from "effect"
|
||||||
import { Bus } from "../../src/bus"
|
import { Bus } from "../../src/bus"
|
||||||
import { runtime } from "../../src/effect/runtime"
|
import { runtime } from "../../src/effect/runtime"
|
||||||
import { Instances } from "../../src/effect/instances"
|
import { Instances } from "../../src/effect/instances"
|
||||||
import { PermissionNext } from "../../src/permission/next"
|
import { PermissionNext } from "../../src/permission"
|
||||||
import * as S from "../../src/permission/service"
|
import * as S from "../../src/permission/service"
|
||||||
import { PermissionID } from "../../src/permission/schema"
|
import { PermissionID } from "../../src/permission/schema"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ import { BashTool } from "../../src/tool/bash"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { Filesystem } from "../../src/util/filesystem"
|
import { Filesystem } from "../../src/util/filesystem"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { tmpdir } from "../fixture/fixture"
|
||||||
import type { PermissionNext } from "../../src/permission/next"
|
import type { PermissionNext } from "../../src/permission"
|
||||||
import { Truncate } from "../../src/tool/truncation"
|
import { Truncate } from "../../src/tool/truncate"
|
||||||
import { SessionID, MessageID } from "../../src/session/schema"
|
import { SessionID, MessageID } from "../../src/session/schema"
|
||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import path from "path"
|
||||||
import type { Tool } from "../../src/tool/tool"
|
import type { Tool } from "../../src/tool/tool"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { assertExternalDirectory } from "../../src/tool/external-directory"
|
import { assertExternalDirectory } from "../../src/tool/external-directory"
|
||||||
import type { PermissionNext } from "../../src/permission/next"
|
import type { PermissionNext } from "../../src/permission"
|
||||||
import { SessionID, MessageID } from "../../src/session/schema"
|
import { SessionID, MessageID } from "../../src/session/schema"
|
||||||
|
|
||||||
const baseCtx: Omit<Tool.Context, "ask"> = {
|
const baseCtx: Omit<Tool.Context, "ask"> = {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { ReadTool } from "../../src/tool/read"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { Filesystem } from "../../src/util/filesystem"
|
import { Filesystem } from "../../src/util/filesystem"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { tmpdir } from "../fixture/fixture"
|
||||||
import { PermissionNext } from "../../src/permission/next"
|
import { PermissionNext } from "../../src/permission"
|
||||||
import { Agent } from "../../src/agent/agent"
|
import { Agent } from "../../src/agent/agent"
|
||||||
import { SessionID, MessageID } from "../../src/session/schema"
|
import { SessionID, MessageID } from "../../src/session/schema"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { pathToFileURL } from "url"
|
import { pathToFileURL } from "url"
|
||||||
import type { PermissionNext } from "../../src/permission/next"
|
import type { PermissionNext } from "../../src/permission"
|
||||||
import type { Tool } from "../../src/tool/tool"
|
import type { Tool } from "../../src/tool/tool"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { SkillTool } from "../../src/tool/skill"
|
import { SkillTool } from "../../src/tool/skill"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { describe, test, expect } from "bun:test"
|
import { describe, test, expect } from "bun:test"
|
||||||
import { NodeFileSystem } from "@effect/platform-node"
|
import { NodeFileSystem } from "@effect/platform-node"
|
||||||
import { Effect, FileSystem, Layer } from "effect"
|
import { Effect, FileSystem, Layer } from "effect"
|
||||||
import { Truncate } from "../../src/tool/truncation"
|
import { Truncate } from "../../src/tool/truncate"
|
||||||
import { TruncateService } from "../../src/tool/truncate-service"
|
import { TruncateEffect } from "../../src/tool/truncate-effect"
|
||||||
import { Identifier } from "../../src/id/id"
|
import { Identifier } from "../../src/id/id"
|
||||||
import { Filesystem } from "../../src/util/filesystem"
|
import { Filesystem } from "../../src/util/filesystem"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
|
@ -129,7 +129,7 @@ describe("Truncate", () => {
|
||||||
|
|
||||||
describe("cleanup", () => {
|
describe("cleanup", () => {
|
||||||
const DAY_MS = 24 * 60 * 60 * 1000
|
const DAY_MS = 24 * 60 * 60 * 1000
|
||||||
const it = testEffect(Layer.mergeAll(TruncateService.layer, NodeFileSystem.layer))
|
const it = testEffect(Layer.mergeAll(TruncateEffect.defaultLayer, NodeFileSystem.layer))
|
||||||
|
|
||||||
it.effect("deletes files older than 7 days and preserves recent files", () =>
|
it.effect("deletes files older than 7 days and preserves recent files", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
|
|
@ -142,7 +142,7 @@ describe("Truncate", () => {
|
||||||
|
|
||||||
yield* writeFileStringScoped(old, "old content")
|
yield* writeFileStringScoped(old, "old content")
|
||||||
yield* writeFileStringScoped(recent, "recent content")
|
yield* writeFileStringScoped(recent, "recent content")
|
||||||
yield* TruncateService.use((s) => s.cleanup())
|
yield* TruncateEffect.Service.use((s) => s.cleanup())
|
||||||
|
|
||||||
expect(yield* fs.exists(old)).toBe(false)
|
expect(yield* fs.exists(old)).toBe(false)
|
||||||
expect(yield* fs.exists(recent)).toBe(true)
|
expect(yield* fs.exists(recent)).toBe(true)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue