refactor(schema): extract shared public schemas (#33571)
This commit is contained in:
parent
60aba622ab
commit
516cfe4e09
130 changed files with 2014 additions and 1593 deletions
37
packages/schema/src/agent.ts
Normal file
37
packages/schema/src/agent.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
export * as Agent from "./agent"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { Model } from "./model"
|
||||
import { Permission } from "./permission"
|
||||
import { Provider } from "./provider"
|
||||
import { PositiveInt, withStatics } from "./schema"
|
||||
|
||||
export const ID = Schema.String.pipe(Schema.brand("AgentV2.ID"))
|
||||
export type ID = typeof ID.Type
|
||||
|
||||
export const Color = Schema.Union([
|
||||
Schema.String.check(Schema.isPattern(/^#[0-9a-fA-F]{6}$/)),
|
||||
Schema.Literals(["primary", "secondary", "accent", "success", "warning", "error", "info"]),
|
||||
])
|
||||
export type Color = typeof Color.Type
|
||||
|
||||
export interface Info extends Schema.Schema.Type<typeof Info> {}
|
||||
export const Info = Schema.Struct({
|
||||
id: ID,
|
||||
model: Model.Ref.pipe(Schema.optional),
|
||||
request: Provider.Request,
|
||||
system: Schema.String.pipe(Schema.optional),
|
||||
description: Schema.String.pipe(Schema.optional),
|
||||
mode: Schema.Literals(["subagent", "primary", "all"]),
|
||||
hidden: Schema.Boolean,
|
||||
color: Color.pipe(Schema.optional),
|
||||
steps: PositiveInt.pipe(Schema.optional),
|
||||
permissions: Permission.Ruleset,
|
||||
})
|
||||
.annotate({ identifier: "AgentV2.Info" })
|
||||
.pipe(
|
||||
withStatics((schema) => ({
|
||||
empty: (id: ID) =>
|
||||
schema.make({ id, request: { headers: {}, body: {} }, mode: "all", hidden: false, permissions: [] }),
|
||||
})),
|
||||
)
|
||||
14
packages/schema/src/command.ts
Normal file
14
packages/schema/src/command.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
export * as Command from "./command"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { Model } from "./model"
|
||||
|
||||
export interface Info extends Schema.Schema.Type<typeof Info> {}
|
||||
export const Info = Schema.Struct({
|
||||
name: Schema.String,
|
||||
template: Schema.String,
|
||||
description: Schema.String.pipe(Schema.optional),
|
||||
agent: Schema.String.pipe(Schema.optional),
|
||||
model: Model.Ref.pipe(Schema.optional),
|
||||
subtask: Schema.Boolean.pipe(Schema.optional),
|
||||
}).annotate({ identifier: "CommandV2.Info" })
|
||||
22
packages/schema/src/connection.ts
Normal file
22
packages/schema/src/connection.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
export * as Connection from "./connection"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { Credential } from "./credential"
|
||||
|
||||
export interface CredentialInfo extends Schema.Schema.Type<typeof CredentialInfo> {}
|
||||
export const CredentialInfo = Schema.Struct({
|
||||
type: Schema.Literal("credential"),
|
||||
id: Credential.ID,
|
||||
label: Schema.String,
|
||||
}).annotate({ identifier: "Connection.CredentialInfo" })
|
||||
|
||||
export interface EnvInfo extends Schema.Schema.Type<typeof EnvInfo> {}
|
||||
export const EnvInfo = Schema.Struct({
|
||||
type: Schema.Literal("env"),
|
||||
name: Schema.String,
|
||||
}).annotate({ identifier: "Connection.EnvInfo" })
|
||||
|
||||
export const Info = Schema.Union([CredentialInfo, EnvInfo])
|
||||
.pipe(Schema.toTaggedUnion("type"))
|
||||
.annotate({ identifier: "Connection.Info" })
|
||||
export type Info = typeof Info.Type
|
||||
34
packages/schema/src/credential.ts
Normal file
34
packages/schema/src/credential.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
export * as Credential from "./credential"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { Integration } from "./integration"
|
||||
import { ascending } from "./identifier"
|
||||
import { NonNegativeInt, withStatics } from "./schema"
|
||||
|
||||
export const ID = Schema.String.pipe(
|
||||
Schema.brand("Credential.ID"),
|
||||
withStatics((schema) => ({ create: () => schema.make("cred_" + ascending()) })),
|
||||
)
|
||||
export type ID = typeof ID.Type
|
||||
|
||||
export interface OAuth extends Schema.Schema.Type<typeof OAuth> {}
|
||||
export const OAuth = Schema.Struct({
|
||||
type: Schema.Literal("oauth"),
|
||||
methodID: Integration.MethodID,
|
||||
refresh: Schema.String,
|
||||
access: Schema.String,
|
||||
expires: NonNegativeInt,
|
||||
metadata: Schema.optional(Schema.Record(Schema.String, Schema.Any)),
|
||||
}).annotate({ identifier: "Credential.OAuth" })
|
||||
|
||||
export interface Key extends Schema.Schema.Type<typeof Key> {}
|
||||
export const Key = Schema.Struct({
|
||||
type: Schema.Literal("key"),
|
||||
key: Schema.String,
|
||||
metadata: Schema.optional(Schema.Record(Schema.String, Schema.Any)),
|
||||
}).annotate({ identifier: "Credential.Key" })
|
||||
|
||||
export const Value = Schema.Union([OAuth, Key])
|
||||
.pipe(Schema.toTaggedUnion("type"))
|
||||
.annotate({ identifier: "Credential.Value" })
|
||||
export type Value = Schema.Schema.Type<typeof Value>
|
||||
26
packages/schema/src/filesystem.ts
Normal file
26
packages/schema/src/filesystem.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
export * as FileSystem from "./filesystem"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { NonNegativeInt, PositiveInt, RelativePath } from "./schema"
|
||||
|
||||
export interface Entry extends Schema.Schema.Type<typeof Entry> {}
|
||||
export const Entry = Schema.Struct({
|
||||
path: RelativePath,
|
||||
type: Schema.Literals(["file", "directory"]),
|
||||
}).annotate({ identifier: "FileSystem.Entry" })
|
||||
|
||||
export interface Submatch extends Schema.Schema.Type<typeof Submatch> {}
|
||||
export const Submatch = Schema.Struct({
|
||||
text: Schema.String,
|
||||
start: NonNegativeInt,
|
||||
end: NonNegativeInt,
|
||||
})
|
||||
|
||||
export interface Match extends Schema.Schema.Type<typeof Match> {}
|
||||
export const Match = Schema.Struct({
|
||||
entry: Entry,
|
||||
line: PositiveInt,
|
||||
offset: NonNegativeInt,
|
||||
text: Schema.String,
|
||||
submatches: Schema.Array(Submatch),
|
||||
}).annotate({ identifier: "FileSystem.Match" })
|
||||
30
packages/schema/src/identifier.ts
Normal file
30
packages/schema/src/identifier.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
const length = 26
|
||||
const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
let lastTimestamp = 0
|
||||
let counter = 0
|
||||
|
||||
export function ascending() {
|
||||
return create(false)
|
||||
}
|
||||
|
||||
export function descending() {
|
||||
return create(true)
|
||||
}
|
||||
|
||||
export function create(descending: boolean, timestamp = Date.now()) {
|
||||
if (timestamp !== lastTimestamp) {
|
||||
lastTimestamp = timestamp
|
||||
counter = 0
|
||||
}
|
||||
counter++
|
||||
|
||||
const current = BigInt(timestamp) * 0x1000n + BigInt(counter)
|
||||
const value = descending ? ~current : current
|
||||
const time = Array.from({ length: 6 }, (_, index) =>
|
||||
Number((value >> BigInt(40 - 8 * index)) & 0xffn)
|
||||
.toString(16)
|
||||
.padStart(2, "0"),
|
||||
).join("")
|
||||
const bytes = crypto.getRandomValues(new Uint8Array(length - 12))
|
||||
return time + Array.from(bytes, (byte) => chars[byte % 62]).join("")
|
||||
}
|
||||
21
packages/schema/src/index.ts
Normal file
21
packages/schema/src/index.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
export { Agent } from "./agent"
|
||||
export { Command } from "./command"
|
||||
export { Connection } from "./connection"
|
||||
export { Credential } from "./credential"
|
||||
export { FileSystem } from "./filesystem"
|
||||
export { Integration } from "./integration"
|
||||
export { LLM } from "./llm"
|
||||
export { Location } from "./location"
|
||||
export { Model } from "./model"
|
||||
export { ModelRequest } from "./model-request"
|
||||
export { Permission } from "./permission"
|
||||
export { Project } from "./project"
|
||||
export { Provider } from "./provider"
|
||||
export { Reference } from "./reference"
|
||||
export { Session } from "./session"
|
||||
export { SessionInput } from "./session-input"
|
||||
export { SessionMessage } from "./session-message"
|
||||
export { Skill } from "./skill"
|
||||
export { Workspace } from "./workspace"
|
||||
export { Prompt, Source, FileAttachment, AgentAttachment } from "./prompt"
|
||||
export * from "./schema"
|
||||
79
packages/schema/src/integration.ts
Normal file
79
packages/schema/src/integration.ts
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
export * as Integration from "./integration"
|
||||
|
||||
import { Schema } from "effect"
|
||||
|
||||
export const ID = Schema.String.pipe(Schema.brand("Integration.ID"))
|
||||
export type ID = typeof ID.Type
|
||||
|
||||
export const MethodID = Schema.String.pipe(Schema.brand("Integration.MethodID"))
|
||||
export type MethodID = typeof MethodID.Type
|
||||
|
||||
export interface When extends Schema.Schema.Type<typeof When> {}
|
||||
export const When = Schema.Struct({
|
||||
key: Schema.String,
|
||||
op: Schema.Literals(["eq", "neq"]),
|
||||
value: Schema.String,
|
||||
}).annotate({ identifier: "Integration.When" })
|
||||
|
||||
export interface TextPrompt extends Schema.Schema.Type<typeof TextPrompt> {}
|
||||
export const TextPrompt = Schema.Struct({
|
||||
type: Schema.Literal("text"),
|
||||
key: Schema.String,
|
||||
message: Schema.String,
|
||||
placeholder: Schema.optional(Schema.String),
|
||||
when: Schema.optional(When),
|
||||
}).annotate({ identifier: "Integration.TextPrompt" })
|
||||
|
||||
export interface SelectPrompt extends Schema.Schema.Type<typeof SelectPrompt> {}
|
||||
export const SelectPrompt = Schema.Struct({
|
||||
type: Schema.Literal("select"),
|
||||
key: Schema.String,
|
||||
message: Schema.String,
|
||||
options: Schema.mutable(
|
||||
Schema.Array(
|
||||
Schema.Struct({
|
||||
label: Schema.String,
|
||||
value: Schema.String,
|
||||
hint: Schema.optional(Schema.String),
|
||||
}),
|
||||
),
|
||||
),
|
||||
when: Schema.optional(When),
|
||||
}).annotate({ identifier: "Integration.SelectPrompt" })
|
||||
|
||||
export const Prompt = Schema.Union([TextPrompt, SelectPrompt]).pipe(Schema.toTaggedUnion("type"))
|
||||
export type Prompt = typeof Prompt.Type
|
||||
|
||||
export interface OAuthMethod extends Schema.Schema.Type<typeof OAuthMethod> {}
|
||||
export const OAuthMethod = Schema.Struct({
|
||||
id: MethodID,
|
||||
type: Schema.Literal("oauth"),
|
||||
label: Schema.String,
|
||||
prompts: Schema.optional(Schema.mutable(Schema.Array(Prompt))),
|
||||
}).annotate({ identifier: "Integration.OAuthMethod" })
|
||||
|
||||
export interface KeyMethod extends Schema.Schema.Type<typeof KeyMethod> {}
|
||||
export const KeyMethod = Schema.Struct({
|
||||
type: Schema.Literal("key"),
|
||||
label: Schema.optional(Schema.String),
|
||||
}).annotate({ identifier: "Integration.KeyMethod" })
|
||||
|
||||
export interface EnvMethod extends Schema.Schema.Type<typeof EnvMethod> {}
|
||||
export const EnvMethod = Schema.Struct({
|
||||
type: Schema.Literal("env"),
|
||||
names: Schema.mutable(Schema.Array(Schema.String)),
|
||||
}).annotate({ identifier: "Integration.EnvMethod" })
|
||||
|
||||
export const Method = Schema.Union([OAuthMethod, KeyMethod, EnvMethod])
|
||||
.pipe(Schema.toTaggedUnion("type"))
|
||||
.annotate({ identifier: "Integration.Method" })
|
||||
export type Method = typeof Method.Type
|
||||
|
||||
export const Inputs = Schema.Record(Schema.String, Schema.String).annotate({ identifier: "Integration.Inputs" })
|
||||
export type Inputs = typeof Inputs.Type
|
||||
|
||||
export interface Ref extends Schema.Schema.Type<typeof Ref> {}
|
||||
export const Ref = Schema.Struct({
|
||||
id: ID,
|
||||
name: Schema.String,
|
||||
}).annotate({ identifier: "Integration.Ref" })
|
||||
23
packages/schema/src/llm.ts
Normal file
23
packages/schema/src/llm.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
export * as LLM from "./llm"
|
||||
|
||||
import { Schema } from "effect"
|
||||
|
||||
export const ProviderMetadata = Schema.Record(Schema.String, Schema.Record(Schema.String, Schema.Unknown))
|
||||
export type ProviderMetadata = Schema.Schema.Type<typeof ProviderMetadata>
|
||||
|
||||
export interface ToolTextContent extends Schema.Schema.Type<typeof ToolTextContent> {}
|
||||
export const ToolTextContent = Schema.Struct({
|
||||
type: Schema.Literal("text"),
|
||||
text: Schema.String,
|
||||
}).annotate({ identifier: "Tool.TextContent" })
|
||||
|
||||
export interface ToolFileContent extends Schema.Schema.Type<typeof ToolFileContent> {}
|
||||
export const ToolFileContent = Schema.Struct({
|
||||
type: Schema.Literal("file"),
|
||||
uri: Schema.String,
|
||||
mime: Schema.String,
|
||||
name: Schema.optional(Schema.String),
|
||||
}).annotate({ identifier: "Tool.FileContent" })
|
||||
|
||||
export const ToolContent = Schema.Union([ToolTextContent, ToolFileContent]).pipe(Schema.toTaggedUnion("type"))
|
||||
export type ToolContent = Schema.Schema.Type<typeof ToolContent>
|
||||
14
packages/schema/src/location.ts
Normal file
14
packages/schema/src/location.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
export * as Location from "./location"
|
||||
|
||||
import { Effect, Schema } from "effect"
|
||||
import { AbsolutePath } from "./schema"
|
||||
import { Workspace } from "./workspace"
|
||||
|
||||
export interface Ref extends Schema.Schema.Type<typeof Ref> {}
|
||||
export const Ref = Schema.Struct({
|
||||
directory: AbsolutePath,
|
||||
workspaceID: Schema.optional(Workspace.ID).pipe(
|
||||
Schema.withDecodingDefault(Effect.succeed(undefined)),
|
||||
Schema.withConstructorDefault(Effect.succeed(undefined)),
|
||||
),
|
||||
}).annotate({ identifier: "Location.Ref" })
|
||||
31
packages/schema/src/model-request.ts
Normal file
31
packages/schema/src/model-request.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
export * as ModelRequest from "./model-request"
|
||||
|
||||
import { Effect, Schema } from "effect"
|
||||
import { Provider } from "./provider"
|
||||
|
||||
export interface Generation extends Schema.Schema.Type<typeof Generation> {}
|
||||
export const Generation = Schema.Struct({
|
||||
maxTokens: Schema.Number.pipe(Schema.optional),
|
||||
temperature: Schema.Number.pipe(Schema.optional),
|
||||
topP: Schema.Number.pipe(Schema.optional),
|
||||
topK: Schema.Number.pipe(Schema.optional),
|
||||
frequencyPenalty: Schema.Number.pipe(Schema.optional),
|
||||
presencePenalty: Schema.Number.pipe(Schema.optional),
|
||||
seed: Schema.Number.pipe(Schema.optional),
|
||||
stop: Schema.String.pipe(Schema.Array, Schema.mutable, Schema.optional),
|
||||
})
|
||||
|
||||
export interface Request extends Schema.Schema.Type<typeof Request> {}
|
||||
export const Request = Schema.Struct({
|
||||
...Provider.Request.fields,
|
||||
generation: Generation.pipe(
|
||||
Schema.optionalKey,
|
||||
Schema.withConstructorDefault(Effect.succeed({})),
|
||||
Schema.withDecodingDefaultKey(Effect.succeed({})),
|
||||
),
|
||||
options: Schema.Record(Schema.String, Schema.Any).pipe(
|
||||
Schema.optionalKey,
|
||||
Schema.withConstructorDefault(Effect.succeed({})),
|
||||
Schema.withDecodingDefaultKey(Effect.succeed({})),
|
||||
),
|
||||
})
|
||||
104
packages/schema/src/model.ts
Normal file
104
packages/schema/src/model.ts
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
export * as Model from "./model"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { ModelRequest } from "./model-request"
|
||||
import { Provider } from "./provider"
|
||||
import { withStatics } from "./schema"
|
||||
|
||||
export const ID = Schema.String.pipe(Schema.brand("ModelV2.ID"))
|
||||
export type ID = typeof ID.Type
|
||||
|
||||
export const VariantID = Schema.String.pipe(Schema.brand("VariantID"))
|
||||
export type VariantID = typeof VariantID.Type
|
||||
|
||||
export const Ref = Schema.Struct({
|
||||
id: ID,
|
||||
providerID: Provider.ID,
|
||||
variant: VariantID.pipe(Schema.optional),
|
||||
})
|
||||
export type Ref = typeof Ref.Type
|
||||
|
||||
export const Family = Schema.String.pipe(Schema.brand("Family"))
|
||||
export type Family = typeof Family.Type
|
||||
|
||||
export interface Capabilities extends Schema.Schema.Type<typeof Capabilities> {}
|
||||
export const Capabilities = Schema.Struct({
|
||||
tools: Schema.Boolean,
|
||||
input: Schema.String.pipe(Schema.Array, Schema.mutable),
|
||||
output: Schema.String.pipe(Schema.Array, Schema.mutable),
|
||||
})
|
||||
|
||||
export interface Cost extends Schema.Schema.Type<typeof Cost> {}
|
||||
export const Cost = Schema.Struct({
|
||||
tier: Schema.Struct({
|
||||
type: Schema.Literal("context"),
|
||||
size: Schema.Int,
|
||||
}).pipe(Schema.optional),
|
||||
input: Schema.Finite,
|
||||
output: Schema.Finite,
|
||||
cache: Schema.Struct({
|
||||
read: Schema.Finite,
|
||||
write: Schema.Finite,
|
||||
}),
|
||||
})
|
||||
|
||||
export const Api = Schema.Union([
|
||||
Schema.Struct({
|
||||
id: ID,
|
||||
...Provider.AISDK.fields,
|
||||
}),
|
||||
Schema.Struct({
|
||||
id: ID,
|
||||
...Provider.Native.fields,
|
||||
}),
|
||||
]).pipe(Schema.toTaggedUnion("type"))
|
||||
export type Api = typeof Api.Type
|
||||
|
||||
export interface Info extends Schema.Schema.Type<typeof Info> {}
|
||||
export const Info = Schema.Struct({
|
||||
id: ID,
|
||||
providerID: Provider.ID,
|
||||
family: Family.pipe(Schema.optional),
|
||||
name: Schema.String,
|
||||
api: Api,
|
||||
capabilities: Capabilities,
|
||||
request: Schema.Struct({
|
||||
...ModelRequest.Request.fields,
|
||||
variant: Schema.String.pipe(Schema.optional),
|
||||
}),
|
||||
variants: Schema.Struct({
|
||||
id: VariantID,
|
||||
...ModelRequest.Request.fields,
|
||||
}).pipe(Schema.Array, Schema.mutable),
|
||||
time: Schema.Struct({
|
||||
released: Schema.Finite,
|
||||
}),
|
||||
cost: Cost.pipe(Schema.Array, Schema.mutable),
|
||||
status: Schema.Literals(["alpha", "beta", "deprecated", "active"]),
|
||||
enabled: Schema.Boolean,
|
||||
limit: Schema.Struct({
|
||||
context: Schema.Int,
|
||||
input: Schema.Int.pipe(Schema.optional),
|
||||
output: Schema.Int,
|
||||
}),
|
||||
})
|
||||
.annotate({ identifier: "ModelV2.Info" })
|
||||
.pipe(
|
||||
withStatics((schema) => ({
|
||||
empty: (providerID: Provider.ID, modelID: ID) =>
|
||||
schema.make({
|
||||
id: modelID,
|
||||
providerID,
|
||||
name: modelID,
|
||||
api: { id: modelID, type: "native", settings: {} },
|
||||
capabilities: { tools: false, input: [], output: [] },
|
||||
request: { headers: {}, body: {}, generation: {}, options: {} },
|
||||
variants: [],
|
||||
time: { released: 0 },
|
||||
cost: [],
|
||||
status: "active",
|
||||
enabled: true,
|
||||
limit: { context: 0, output: 0 },
|
||||
}),
|
||||
})),
|
||||
)
|
||||
16
packages/schema/src/permission.ts
Normal file
16
packages/schema/src/permission.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
export * as Permission from "./permission"
|
||||
|
||||
import { Schema } from "effect"
|
||||
|
||||
export const Effect = Schema.Literals(["allow", "deny", "ask"]).annotate({ identifier: "PermissionV2.Effect" })
|
||||
export type Effect = typeof Effect.Type
|
||||
|
||||
export interface Rule extends Schema.Schema.Type<typeof Rule> {}
|
||||
export const Rule = Schema.Struct({
|
||||
action: Schema.String,
|
||||
resource: Schema.String,
|
||||
effect: Effect,
|
||||
}).annotate({ identifier: "PermissionV2.Rule" })
|
||||
|
||||
export const Ruleset = Schema.mutable(Schema.Array(Rule)).annotate({ identifier: "PermissionV2.Ruleset" })
|
||||
export type Ruleset = typeof Ruleset.Type
|
||||
10
packages/schema/src/project.ts
Normal file
10
packages/schema/src/project.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export * as Project from "./project"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { withStatics } from "./schema"
|
||||
|
||||
export const ID = Schema.String.pipe(
|
||||
Schema.brand("Project.ID"),
|
||||
withStatics((schema) => ({ global: schema.make("global") })),
|
||||
)
|
||||
export type ID = typeof ID.Type
|
||||
56
packages/schema/src/prompt.ts
Normal file
56
packages/schema/src/prompt.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import { Schema } from "effect"
|
||||
import { withStatics } from "./schema"
|
||||
|
||||
export interface Source extends Schema.Schema.Type<typeof Source> {}
|
||||
export const Source = Schema.Struct({
|
||||
start: Schema.Finite,
|
||||
end: Schema.Finite,
|
||||
text: Schema.String,
|
||||
}).annotate({ identifier: "Prompt.Source" })
|
||||
|
||||
export interface FileAttachment extends Schema.Schema.Type<typeof FileAttachment> {}
|
||||
export const FileAttachment = Schema.Struct({
|
||||
uri: Schema.String,
|
||||
mime: Schema.String,
|
||||
name: Schema.String.pipe(Schema.optional),
|
||||
description: Schema.String.pipe(Schema.optional),
|
||||
source: Source.pipe(Schema.optional),
|
||||
})
|
||||
.annotate({ identifier: "Prompt.FileAttachment" })
|
||||
.pipe(
|
||||
withStatics((schema) => ({
|
||||
create: (input: FileAttachment) =>
|
||||
schema.make({
|
||||
uri: input.uri,
|
||||
mime: input.mime,
|
||||
name: input.name,
|
||||
description: input.description,
|
||||
source: input.source,
|
||||
}),
|
||||
})),
|
||||
)
|
||||
|
||||
export interface AgentAttachment extends Schema.Schema.Type<typeof AgentAttachment> {}
|
||||
export const AgentAttachment = Schema.Struct({
|
||||
name: Schema.String,
|
||||
source: Source.pipe(Schema.optional),
|
||||
}).annotate({ identifier: "Prompt.AgentAttachment" })
|
||||
|
||||
export interface Prompt extends Schema.Schema.Type<typeof Prompt> {}
|
||||
export const Prompt = Schema.Struct({
|
||||
text: Schema.String,
|
||||
files: Schema.Array(FileAttachment).pipe(Schema.optional),
|
||||
agents: Schema.Array(AgentAttachment).pipe(Schema.optional),
|
||||
})
|
||||
.annotate({ identifier: "Prompt" })
|
||||
.pipe(
|
||||
withStatics((schema) => ({
|
||||
equivalence: Schema.toEquivalence(schema),
|
||||
fromUserMessage: (input: Pick<Prompt, "text" | "files" | "agents">) =>
|
||||
schema.make({
|
||||
text: input.text,
|
||||
...(input.files === undefined ? {} : { files: input.files }),
|
||||
...(input.agents === undefined ? {} : { agents: input.agents }),
|
||||
}),
|
||||
})),
|
||||
)
|
||||
69
packages/schema/src/provider.ts
Normal file
69
packages/schema/src/provider.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
export * as Provider from "./provider"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { Integration } from "./integration"
|
||||
import { withStatics } from "./schema"
|
||||
|
||||
export const ID = Schema.String.pipe(
|
||||
Schema.brand("ProviderV2.ID"),
|
||||
withStatics((schema) => ({
|
||||
opencode: schema.make("opencode"),
|
||||
anthropic: schema.make("anthropic"),
|
||||
openai: schema.make("openai"),
|
||||
google: schema.make("google"),
|
||||
googleVertex: schema.make("google-vertex"),
|
||||
githubCopilot: schema.make("github-copilot"),
|
||||
amazonBedrock: schema.make("amazon-bedrock"),
|
||||
azure: schema.make("azure"),
|
||||
openrouter: schema.make("openrouter"),
|
||||
mistral: schema.make("mistral"),
|
||||
gitlab: schema.make("gitlab"),
|
||||
})),
|
||||
)
|
||||
export type ID = typeof ID.Type
|
||||
|
||||
export interface AISDK extends Schema.Schema.Type<typeof AISDK> {}
|
||||
export const AISDK = Schema.Struct({
|
||||
type: Schema.Literal("aisdk"),
|
||||
package: Schema.String,
|
||||
url: Schema.String.pipe(Schema.optional),
|
||||
settings: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
||||
})
|
||||
|
||||
export interface Native extends Schema.Schema.Type<typeof Native> {}
|
||||
export const Native = Schema.Struct({
|
||||
type: Schema.Literal("native"),
|
||||
url: Schema.String.pipe(Schema.optional),
|
||||
settings: Schema.Record(Schema.String, Schema.Unknown),
|
||||
})
|
||||
|
||||
export const Api = Schema.Union([AISDK, Native]).pipe(Schema.toTaggedUnion("type"))
|
||||
export type Api = typeof Api.Type
|
||||
|
||||
export interface Request extends Schema.Schema.Type<typeof Request> {}
|
||||
export const Request = Schema.Struct({
|
||||
headers: Schema.Record(Schema.String, Schema.String),
|
||||
body: Schema.Record(Schema.String, Schema.Any),
|
||||
})
|
||||
|
||||
export interface Info extends Schema.Schema.Type<typeof Info> {}
|
||||
export const Info = Schema.Struct({
|
||||
id: ID,
|
||||
integrationID: Integration.ID.pipe(Schema.optional),
|
||||
name: Schema.String,
|
||||
disabled: Schema.Boolean.pipe(Schema.optional),
|
||||
api: Api,
|
||||
request: Request,
|
||||
})
|
||||
.annotate({ identifier: "ProviderV2.Info" })
|
||||
.pipe(
|
||||
withStatics((schema) => ({
|
||||
empty: (id: ID) =>
|
||||
schema.make({
|
||||
id,
|
||||
name: id,
|
||||
api: { type: "native", settings: {} },
|
||||
request: { headers: {}, body: {} },
|
||||
}),
|
||||
})),
|
||||
)
|
||||
24
packages/schema/src/reference.ts
Normal file
24
packages/schema/src/reference.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
export * as Reference from "./reference"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { AbsolutePath } from "./schema"
|
||||
|
||||
export interface LocalSource extends Schema.Schema.Type<typeof LocalSource> {}
|
||||
export const LocalSource = Schema.Struct({
|
||||
type: Schema.Literal("local"),
|
||||
path: AbsolutePath,
|
||||
description: Schema.String.pipe(Schema.optional),
|
||||
hidden: Schema.Boolean.pipe(Schema.optional),
|
||||
}).annotate({ identifier: "Reference.LocalSource" })
|
||||
|
||||
export interface GitSource extends Schema.Schema.Type<typeof GitSource> {}
|
||||
export const GitSource = Schema.Struct({
|
||||
type: Schema.Literal("git"),
|
||||
repository: Schema.String,
|
||||
branch: Schema.String.pipe(Schema.optional),
|
||||
description: Schema.String.pipe(Schema.optional),
|
||||
hidden: Schema.Boolean.pipe(Schema.optional),
|
||||
}).annotate({ identifier: "Reference.GitSource" })
|
||||
|
||||
export const Source = Schema.Union([LocalSource, GitSource]).pipe(Schema.toTaggedUnion("type"))
|
||||
export type Source = typeof Source.Type
|
||||
30
packages/schema/src/schema.ts
Normal file
30
packages/schema/src/schema.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { DateTime, Option, Schema, SchemaGetter } from "effect"
|
||||
|
||||
export const PositiveInt = Schema.Int.check(Schema.isGreaterThan(0))
|
||||
export const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))
|
||||
|
||||
export const RelativePath = Schema.String.pipe(Schema.brand("RelativePath"))
|
||||
export type RelativePath = typeof RelativePath.Type
|
||||
|
||||
export const AbsolutePath = Schema.String.pipe(Schema.brand("AbsolutePath"))
|
||||
export type AbsolutePath = typeof AbsolutePath.Type
|
||||
|
||||
export const optionalOmitUndefined = <S extends Schema.Top>(schema: S) =>
|
||||
Schema.optionalKey(schema).pipe(
|
||||
Schema.decodeTo(Schema.optional(schema), {
|
||||
decode: SchemaGetter.passthrough({ strict: false }),
|
||||
encode: SchemaGetter.transformOptional(Option.filter((value) => value !== undefined)),
|
||||
}),
|
||||
)
|
||||
|
||||
export const withStatics =
|
||||
<S extends object, M extends Record<string, unknown>>(methods: (schema: S) => M) =>
|
||||
(schema: S): S & M =>
|
||||
Object.assign(schema, methods(schema))
|
||||
|
||||
export const DateTimeUtcFromMillis = Schema.Finite.pipe(
|
||||
Schema.decodeTo(Schema.DateTimeUtc, {
|
||||
decode: SchemaGetter.transform((value) => DateTime.makeUnsafe(value)),
|
||||
encode: SchemaGetter.transform((value) => DateTime.toEpochMillis(value)),
|
||||
}),
|
||||
)
|
||||
6
packages/schema/src/session-delivery.ts
Normal file
6
packages/schema/src/session-delivery.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export * as SessionDelivery from "./session-delivery"
|
||||
|
||||
import { Schema } from "effect"
|
||||
|
||||
export const Delivery = Schema.Literals(["steer", "queue"])
|
||||
export type Delivery = typeof Delivery.Type
|
||||
17
packages/schema/src/session-id.ts
Normal file
17
packages/schema/src/session-id.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
export * as SessionID from "./session-id"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { descending } from "./identifier"
|
||||
import { withStatics } from "./schema"
|
||||
|
||||
export const ID = Schema.String.check(Schema.isStartsWith("ses")).pipe(
|
||||
Schema.brand("SessionID"),
|
||||
withStatics((schema) => {
|
||||
const create = () => schema.make("ses_" + descending())
|
||||
return {
|
||||
create,
|
||||
descending: (id?: string) => (id === undefined ? create() : schema.make(id)),
|
||||
}
|
||||
}),
|
||||
)
|
||||
export type ID = typeof ID.Type
|
||||
22
packages/schema/src/session-input.ts
Normal file
22
packages/schema/src/session-input.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
export * as SessionInput from "./session-input"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { Prompt } from "./prompt"
|
||||
import { DateTimeUtcFromMillis, NonNegativeInt } from "./schema"
|
||||
import { SessionDelivery } from "./session-delivery"
|
||||
import { SessionID } from "./session-id"
|
||||
import { SessionMessageID } from "./session-message-id"
|
||||
|
||||
export const Delivery = SessionDelivery.Delivery
|
||||
export type Delivery = SessionDelivery.Delivery
|
||||
|
||||
export interface Admitted extends Schema.Schema.Type<typeof Admitted> {}
|
||||
export const Admitted = Schema.Struct({
|
||||
admittedSeq: NonNegativeInt,
|
||||
id: SessionMessageID.ID,
|
||||
sessionID: SessionID.ID,
|
||||
prompt: Prompt,
|
||||
delivery: Delivery,
|
||||
timeCreated: DateTimeUtcFromMillis,
|
||||
promotedSeq: NonNegativeInt.pipe(Schema.optional),
|
||||
}).annotate({ identifier: "SessionInput.Admitted" })
|
||||
11
packages/schema/src/session-message-id.ts
Normal file
11
packages/schema/src/session-message-id.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
export * as SessionMessageID from "./session-message-id"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { ascending } from "./identifier"
|
||||
import { withStatics } from "./schema"
|
||||
|
||||
export const ID = Schema.String.check(Schema.isStartsWith("msg_")).pipe(
|
||||
Schema.brand("Session.Message.ID"),
|
||||
withStatics((schema) => ({ create: () => schema.make("msg_" + ascending()) })),
|
||||
)
|
||||
export type ID = typeof ID.Type
|
||||
204
packages/schema/src/session-message.ts
Normal file
204
packages/schema/src/session-message.ts
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
export * as SessionMessage from "./session-message"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { ProviderMetadata, ToolContent } from "./llm"
|
||||
import { Model } from "./model"
|
||||
import { FileAttachment, Prompt } from "./prompt"
|
||||
import { DateTimeUtcFromMillis } from "./schema"
|
||||
import { SessionID } from "./session-id"
|
||||
import { SessionMessageID } from "./session-message-id"
|
||||
|
||||
export const ID = SessionMessageID.ID
|
||||
export type ID = SessionMessageID.ID
|
||||
|
||||
export interface UnknownError extends Schema.Schema.Type<typeof UnknownError> {}
|
||||
export const UnknownError = Schema.Struct({
|
||||
type: Schema.Literal("unknown"),
|
||||
message: Schema.String,
|
||||
}).annotate({ identifier: "Session.Error.Unknown" })
|
||||
|
||||
const Base = {
|
||||
id: ID,
|
||||
metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
||||
time: Schema.Struct({ created: DateTimeUtcFromMillis }),
|
||||
}
|
||||
|
||||
export interface AgentSwitched extends Schema.Schema.Type<typeof AgentSwitched> {}
|
||||
export const AgentSwitched = Schema.Struct({
|
||||
...Base,
|
||||
type: Schema.Literal("agent-switched"),
|
||||
agent: Schema.String,
|
||||
}).annotate({ identifier: "Session.Message.AgentSwitched" })
|
||||
|
||||
export interface ModelSwitched extends Schema.Schema.Type<typeof ModelSwitched> {}
|
||||
export const ModelSwitched = Schema.Struct({
|
||||
...Base,
|
||||
type: Schema.Literal("model-switched"),
|
||||
model: Model.Ref,
|
||||
}).annotate({ identifier: "Session.Message.ModelSwitched" })
|
||||
|
||||
export interface User extends Schema.Schema.Type<typeof User> {}
|
||||
export const User = Schema.Struct({
|
||||
...Base,
|
||||
text: Prompt.fields.text,
|
||||
files: Prompt.fields.files,
|
||||
agents: Prompt.fields.agents,
|
||||
type: Schema.Literal("user"),
|
||||
}).annotate({ identifier: "Session.Message.User" })
|
||||
|
||||
export interface Synthetic extends Schema.Schema.Type<typeof Synthetic> {}
|
||||
export const Synthetic = Schema.Struct({
|
||||
...Base,
|
||||
sessionID: SessionID.ID,
|
||||
text: Schema.String,
|
||||
type: Schema.Literal("synthetic"),
|
||||
}).annotate({ identifier: "Session.Message.Synthetic" })
|
||||
|
||||
export interface System extends Schema.Schema.Type<typeof System> {}
|
||||
export const System = Schema.Struct({
|
||||
...Base,
|
||||
type: Schema.Literal("system"),
|
||||
text: Schema.String,
|
||||
}).annotate({ identifier: "Session.Message.System" })
|
||||
|
||||
export interface Shell extends Schema.Schema.Type<typeof Shell> {}
|
||||
export const Shell = Schema.Struct({
|
||||
...Base,
|
||||
type: Schema.Literal("shell"),
|
||||
callID: Schema.String,
|
||||
command: Schema.String,
|
||||
output: Schema.String,
|
||||
time: Schema.Struct({
|
||||
created: DateTimeUtcFromMillis,
|
||||
completed: DateTimeUtcFromMillis.pipe(Schema.optional),
|
||||
}),
|
||||
}).annotate({ identifier: "Session.Message.Shell" })
|
||||
|
||||
export interface ToolStatePending extends Schema.Schema.Type<typeof ToolStatePending> {}
|
||||
export const ToolStatePending = Schema.Struct({
|
||||
status: Schema.Literal("pending"),
|
||||
input: Schema.String,
|
||||
}).annotate({ identifier: "Session.Message.ToolState.Pending" })
|
||||
|
||||
export interface ToolStateRunning extends Schema.Schema.Type<typeof ToolStateRunning> {}
|
||||
export const ToolStateRunning = Schema.Struct({
|
||||
status: Schema.Literal("running"),
|
||||
input: Schema.Record(Schema.String, Schema.Unknown),
|
||||
structured: Schema.Record(Schema.String, Schema.Any),
|
||||
content: ToolContent.pipe(Schema.Array),
|
||||
}).annotate({ identifier: "Session.Message.ToolState.Running" })
|
||||
|
||||
export interface ToolStateCompleted extends Schema.Schema.Type<typeof ToolStateCompleted> {}
|
||||
export const ToolStateCompleted = Schema.Struct({
|
||||
status: Schema.Literal("completed"),
|
||||
input: Schema.Record(Schema.String, Schema.Unknown),
|
||||
attachments: FileAttachment.pipe(Schema.Array, Schema.optional),
|
||||
content: ToolContent.pipe(Schema.Array),
|
||||
outputPaths: Schema.Array(Schema.String).pipe(Schema.optional),
|
||||
structured: Schema.Record(Schema.String, Schema.Any),
|
||||
result: Schema.Unknown.pipe(Schema.optional),
|
||||
}).annotate({ identifier: "Session.Message.ToolState.Completed" })
|
||||
|
||||
export interface ToolStateError extends Schema.Schema.Type<typeof ToolStateError> {}
|
||||
export const ToolStateError = Schema.Struct({
|
||||
status: Schema.Literal("error"),
|
||||
input: Schema.Record(Schema.String, Schema.Unknown),
|
||||
content: ToolContent.pipe(Schema.Array),
|
||||
structured: Schema.Record(Schema.String, Schema.Any),
|
||||
error: UnknownError,
|
||||
result: Schema.Unknown.pipe(Schema.optional),
|
||||
}).annotate({ identifier: "Session.Message.ToolState.Error" })
|
||||
|
||||
export const ToolState = Schema.Union([ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError]).pipe(
|
||||
Schema.toTaggedUnion("status"),
|
||||
)
|
||||
export type ToolState = ToolStatePending | ToolStateRunning | ToolStateCompleted | ToolStateError
|
||||
|
||||
export interface AssistantTool extends Schema.Schema.Type<typeof AssistantTool> {}
|
||||
export const AssistantTool = Schema.Struct({
|
||||
type: Schema.Literal("tool"),
|
||||
id: Schema.String,
|
||||
name: Schema.String,
|
||||
provider: Schema.Struct({
|
||||
executed: Schema.Boolean,
|
||||
metadata: ProviderMetadata.pipe(Schema.optional),
|
||||
resultMetadata: ProviderMetadata.pipe(Schema.optional),
|
||||
}).pipe(Schema.optional),
|
||||
state: ToolState,
|
||||
time: Schema.Struct({
|
||||
created: DateTimeUtcFromMillis,
|
||||
ran: DateTimeUtcFromMillis.pipe(Schema.optional),
|
||||
completed: DateTimeUtcFromMillis.pipe(Schema.optional),
|
||||
pruned: DateTimeUtcFromMillis.pipe(Schema.optional),
|
||||
}),
|
||||
}).annotate({ identifier: "Session.Message.Assistant.Tool" })
|
||||
|
||||
export interface AssistantText extends Schema.Schema.Type<typeof AssistantText> {}
|
||||
export const AssistantText = Schema.Struct({
|
||||
type: Schema.Literal("text"),
|
||||
id: Schema.String,
|
||||
text: Schema.String,
|
||||
}).annotate({ identifier: "Session.Message.Assistant.Text" })
|
||||
|
||||
export interface AssistantReasoning extends Schema.Schema.Type<typeof AssistantReasoning> {}
|
||||
export const AssistantReasoning = Schema.Struct({
|
||||
type: Schema.Literal("reasoning"),
|
||||
id: Schema.String,
|
||||
text: Schema.String,
|
||||
providerMetadata: ProviderMetadata.pipe(Schema.optional),
|
||||
}).annotate({ identifier: "Session.Message.Assistant.Reasoning" })
|
||||
|
||||
export const AssistantContent = Schema.Union([AssistantText, AssistantReasoning, AssistantTool]).pipe(
|
||||
Schema.toTaggedUnion("type"),
|
||||
)
|
||||
export type AssistantContent = AssistantText | AssistantReasoning | AssistantTool
|
||||
|
||||
export interface Assistant extends Schema.Schema.Type<typeof Assistant> {}
|
||||
export const Assistant = Schema.Struct({
|
||||
...Base,
|
||||
type: Schema.Literal("assistant"),
|
||||
agent: Schema.String,
|
||||
model: Model.Ref,
|
||||
content: AssistantContent.pipe(Schema.Array),
|
||||
snapshot: Schema.Struct({
|
||||
start: Schema.String.pipe(Schema.optional),
|
||||
end: Schema.String.pipe(Schema.optional),
|
||||
}).pipe(Schema.optional),
|
||||
finish: Schema.String.pipe(Schema.optional),
|
||||
cost: Schema.Finite.pipe(Schema.optional),
|
||||
tokens: Schema.Struct({
|
||||
input: Schema.Finite,
|
||||
output: Schema.Finite,
|
||||
reasoning: Schema.Finite,
|
||||
cache: Schema.Struct({ read: Schema.Finite, write: Schema.Finite }),
|
||||
}).pipe(Schema.optional),
|
||||
error: UnknownError.pipe(Schema.optional),
|
||||
time: Schema.Struct({
|
||||
created: DateTimeUtcFromMillis,
|
||||
completed: DateTimeUtcFromMillis.pipe(Schema.optional),
|
||||
}),
|
||||
}).annotate({ identifier: "Session.Message.Assistant" })
|
||||
|
||||
export interface Compaction extends Schema.Schema.Type<typeof Compaction> {}
|
||||
export const Compaction = Schema.Struct({
|
||||
type: Schema.Literal("compaction"),
|
||||
reason: Schema.Literals(["auto", "manual"]),
|
||||
summary: Schema.String,
|
||||
recent: Schema.String,
|
||||
...Base,
|
||||
}).annotate({ identifier: "Session.Message.Compaction" })
|
||||
|
||||
export const Message = Schema.Union([
|
||||
AgentSwitched,
|
||||
ModelSwitched,
|
||||
User,
|
||||
Synthetic,
|
||||
System,
|
||||
Shell,
|
||||
Assistant,
|
||||
Compaction,
|
||||
])
|
||||
.pipe(Schema.toTaggedUnion("type"))
|
||||
.annotate({ identifier: "Session.Message" })
|
||||
export type Message = AgentSwitched | ModelSwitched | User | Synthetic | System | Shell | Assistant | Compaction
|
||||
export type Type = Message["type"]
|
||||
46
packages/schema/src/session.ts
Normal file
46
packages/schema/src/session.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
export * as Session from "./session"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { Agent } from "./agent"
|
||||
import { Location } from "./location"
|
||||
import { Model } from "./model"
|
||||
import { Project } from "./project"
|
||||
import { DateTimeUtcFromMillis, optionalOmitUndefined, RelativePath } from "./schema"
|
||||
import { SessionID } from "./session-id"
|
||||
|
||||
export const ID = SessionID.ID
|
||||
export type ID = SessionID.ID
|
||||
|
||||
export interface Info extends Schema.Schema.Type<typeof Info> {}
|
||||
export const Info = Schema.Struct({
|
||||
id: ID,
|
||||
parentID: ID.pipe(optionalOmitUndefined),
|
||||
projectID: Project.ID,
|
||||
agent: Agent.ID.pipe(Schema.optional),
|
||||
model: Model.Ref.pipe(Schema.optional),
|
||||
cost: Schema.Finite,
|
||||
tokens: Schema.Struct({
|
||||
input: Schema.Finite,
|
||||
output: Schema.Finite,
|
||||
reasoning: Schema.Finite,
|
||||
cache: Schema.Struct({
|
||||
read: Schema.Finite,
|
||||
write: Schema.Finite,
|
||||
}),
|
||||
}),
|
||||
time: Schema.Struct({
|
||||
created: DateTimeUtcFromMillis,
|
||||
updated: DateTimeUtcFromMillis,
|
||||
archived: DateTimeUtcFromMillis.pipe(Schema.optional),
|
||||
}),
|
||||
title: Schema.String,
|
||||
location: Location.Ref,
|
||||
subpath: RelativePath.pipe(Schema.optional),
|
||||
}).annotate({ identifier: "SessionV2.Info" })
|
||||
|
||||
export const ListAnchor = Schema.Struct({
|
||||
id: ID,
|
||||
time: Schema.Finite,
|
||||
direction: Schema.Literals(["previous", "next"]),
|
||||
})
|
||||
export type ListAnchor = typeof ListAnchor.Type
|
||||
54
packages/schema/src/skill.ts
Normal file
54
packages/schema/src/skill.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
export * as Skill from "./skill"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { AbsolutePath } from "./schema"
|
||||
|
||||
export interface DirectorySource extends Schema.Schema.Type<typeof DirectorySource> {}
|
||||
export const DirectorySource = Schema.Struct({
|
||||
type: Schema.Literal("directory"),
|
||||
path: AbsolutePath,
|
||||
}).annotate({ identifier: "SkillV2.DirectorySource" })
|
||||
|
||||
export interface UrlSource extends Schema.Schema.Type<typeof UrlSource> {}
|
||||
export const UrlSource = Schema.Struct({
|
||||
type: Schema.Literal("url"),
|
||||
url: Schema.String,
|
||||
}).annotate({ identifier: "SkillV2.UrlSource" })
|
||||
|
||||
export interface Info extends Schema.Schema.Type<typeof Info> {}
|
||||
export const Info = Schema.Struct({
|
||||
name: Schema.String,
|
||||
description: Schema.String.pipe(Schema.optional),
|
||||
slash: Schema.Boolean.pipe(Schema.optional),
|
||||
location: AbsolutePath,
|
||||
content: Schema.String,
|
||||
}).annotate({ identifier: "SkillV2.Info" })
|
||||
|
||||
export interface EmbeddedSource extends Schema.Schema.Type<typeof EmbeddedSource> {}
|
||||
export const EmbeddedSource = Schema.Struct({
|
||||
type: Schema.Literal("embedded"),
|
||||
skill: Schema.suspend(() => Info),
|
||||
}).annotate({ identifier: "SkillV2.EmbeddedSource" })
|
||||
|
||||
export type Source = DirectorySource | UrlSource | EmbeddedSource
|
||||
export const Source = Object.assign(
|
||||
Schema.Union([DirectorySource, UrlSource, EmbeddedSource]).pipe(
|
||||
Schema.toTaggedUnion("type"),
|
||||
Schema.annotate({ identifier: "SkillV2.Source" }),
|
||||
),
|
||||
{
|
||||
equals: (a: Source, b: Source) => {
|
||||
if (a.type !== b.type) return false
|
||||
if (a.type === "directory" && b.type === "directory") return a.path === b.path
|
||||
if (a.type === "url" && b.type === "url") return a.url === b.url
|
||||
if (a.type === "embedded" && b.type === "embedded") return a.skill.name === b.skill.name
|
||||
return false
|
||||
},
|
||||
key: (source: Source) =>
|
||||
source.type === "directory"
|
||||
? `directory:${source.path}`
|
||||
: source.type === "url"
|
||||
? `url:${source.url}`
|
||||
: `embedded:${source.skill.name}`,
|
||||
},
|
||||
)
|
||||
21
packages/schema/src/workspace.ts
Normal file
21
packages/schema/src/workspace.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
export * as Workspace from "./workspace"
|
||||
|
||||
import { Schema } from "effect"
|
||||
import { ascending } from "./identifier"
|
||||
import { withStatics } from "./schema"
|
||||
|
||||
export const ID = Schema.String.check(Schema.isStartsWith("wrk")).pipe(
|
||||
Schema.brand("WorkspaceV2.ID"),
|
||||
withStatics((schema) => {
|
||||
const create = () => schema.make("wrk_" + ascending())
|
||||
return {
|
||||
ascending: (id?: string) => {
|
||||
if (!id) return create()
|
||||
if (!id.startsWith("wrk")) throw new Error(`ID ${id} does not start with wrk`)
|
||||
return schema.make(id)
|
||||
},
|
||||
create,
|
||||
}
|
||||
}),
|
||||
)
|
||||
export type ID = typeof ID.Type
|
||||
Loading…
Add table
Add a link
Reference in a new issue