export * as PermissionLegacy from "./legacy" import { Schema } from "effect" import { ProjectV2 } from "../project" import { withStatics } from "../schema" import { SessionSchema } from "../session/schema" import { Identifier } from "../util/identifier" export const ID = Schema.String.check(Schema.isStartsWith("per")).pipe( Schema.brand("PermissionID"), withStatics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "per_" + Identifier.ascending()) })), ) export type ID = typeof ID.Type export const Action = Schema.Literals(["allow", "deny", "ask"]).annotate({ identifier: "PermissionAction" }) export type Action = typeof Action.Type export const Rule = Schema.Struct({ permission: Schema.String, pattern: Schema.String, action: Action, }).annotate({ identifier: "PermissionRule" }) export type Rule = typeof Rule.Type export const Ruleset = Schema.Array(Rule).annotate({ identifier: "PermissionRuleset" }) export type Ruleset = typeof Ruleset.Type export const Request = Schema.Struct({ id: ID, sessionID: SessionSchema.ID, permission: Schema.String, patterns: Schema.Array(Schema.String), metadata: Schema.Record(Schema.String, Schema.Unknown), always: Schema.Array(Schema.String), tool: Schema.Struct({ messageID: Schema.String, callID: Schema.String, }).pipe(Schema.optional), }).annotate({ identifier: "PermissionRequest" }) export type Request = typeof Request.Type export const Reply = Schema.Literals(["once", "always", "reject"]) export type Reply = typeof Reply.Type export const ReplyBody = Schema.Struct({ reply: Reply, message: Schema.String.pipe(Schema.optional), }).annotate({ identifier: "PermissionReplyBody" }) export type ReplyBody = typeof ReplyBody.Type export const Approval = Schema.Struct({ projectID: ProjectV2.ID, patterns: Schema.Array(Schema.String), }).annotate({ identifier: "PermissionApproval" }) export type Approval = typeof Approval.Type export const AskInput = Schema.Struct({ ...Request.fields, id: ID.pipe(Schema.optional), ruleset: Ruleset, }).annotate({ identifier: "PermissionAskInput" }) export type AskInput = typeof AskInput.Type export const ReplyInput = Schema.Struct({ requestID: ID, ...ReplyBody.fields, }).annotate({ identifier: "PermissionReplyInput" }) export type ReplyInput = typeof ReplyInput.Type export class RejectedError extends Schema.TaggedErrorClass()("PermissionRejectedError", {}) { override get message() { return "The user rejected permission to use this specific tool call." } } export class CorrectedError extends Schema.TaggedErrorClass()("PermissionCorrectedError", { feedback: Schema.String, }) { override get message() { return `The user rejected permission to use this specific tool call with the following feedback: ${this.feedback}` } } export class DeniedError extends Schema.TaggedErrorClass()("PermissionDeniedError", { ruleset: Schema.Any, }) { override get message() { return `The user has specified a rule which prevents you from using this specific tool call. Here are some of the relevant rules ${JSON.stringify(this.ruleset)}` } } export class NotFoundError extends Schema.TaggedErrorClass()("Permission.NotFoundError", { requestID: ID, }) {} export type Error = DeniedError | RejectedError | CorrectedError