refactor(form): model links as fields (#36129)
This commit is contained in:
parent
6a85f0d3db
commit
a6449cb45c
24 changed files with 2409 additions and 1430 deletions
|
|
@ -94,10 +94,27 @@ export const MultiselectField = Schema.Struct({
|
|||
}).annotate({ identifier: "Form.MultiselectField" })
|
||||
export interface MultiselectField extends Schema.Schema.Type<typeof MultiselectField> {}
|
||||
|
||||
export const Field = Schema.Union([StringField, NumberField, IntegerField, BooleanField, MultiselectField]).pipe(
|
||||
Schema.toTaggedUnion("type"),
|
||||
)
|
||||
export type Field = StringField | NumberField | IntegerField | BooleanField | MultiselectField
|
||||
export const ExternalField = Schema.Struct({
|
||||
key: Schema.String,
|
||||
type: Schema.Literal("external"),
|
||||
url: Schema.String,
|
||||
title: Schema.String.pipe(optional),
|
||||
description: Schema.String.pipe(optional),
|
||||
}).annotate({ identifier: "Form.ExternalField" })
|
||||
export interface ExternalField extends Schema.Schema.Type<typeof ExternalField> {}
|
||||
|
||||
export const Field = Schema.Union([
|
||||
StringField,
|
||||
NumberField,
|
||||
IntegerField,
|
||||
BooleanField,
|
||||
MultiselectField,
|
||||
ExternalField,
|
||||
]).pipe(Schema.toTaggedUnion("type"), Schema.annotate({ identifier: "Form.Field" }))
|
||||
export type Field = StringField | NumberField | IntegerField | BooleanField | MultiselectField | ExternalField
|
||||
|
||||
export const Fields = Schema.NonEmptyArray(Field).annotate({ identifier: "Form.Fields" })
|
||||
export type Fields = typeof Fields.Type
|
||||
|
||||
const InfoBase = {
|
||||
id: ID,
|
||||
|
|
@ -110,22 +127,11 @@ const InfoBase = {
|
|||
metadata: Metadata.pipe(optional),
|
||||
}
|
||||
|
||||
export const FormInfo = Schema.Struct({
|
||||
export const Info = Schema.Struct({
|
||||
...InfoBase,
|
||||
mode: Schema.Literal("form"),
|
||||
fields: Schema.Array(Field),
|
||||
}).annotate({ identifier: "Form.FormInfo" })
|
||||
export interface FormInfo extends Schema.Schema.Type<typeof FormInfo> {}
|
||||
|
||||
export const UrlInfo = Schema.Struct({
|
||||
...InfoBase,
|
||||
mode: Schema.Literal("url"),
|
||||
url: Schema.String,
|
||||
}).annotate({ identifier: "Form.UrlInfo" })
|
||||
export interface UrlInfo extends Schema.Schema.Type<typeof UrlInfo> {}
|
||||
|
||||
export const Info = Schema.Union([FormInfo, UrlInfo]).pipe(Schema.toTaggedUnion("mode"))
|
||||
export type Info = FormInfo | UrlInfo
|
||||
fields: Fields,
|
||||
}).annotate({ identifier: "Form.Info" })
|
||||
export interface Info extends Schema.Schema.Type<typeof Info> {}
|
||||
|
||||
export const Value = Schema.Union([Schema.String, Schema.Number, Schema.Boolean, Schema.Array(Schema.String)]).annotate(
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test"
|
|||
import { DateTime, Schema } from "effect"
|
||||
import { Agent } from "../src/agent.js"
|
||||
import { FileSystem } from "../src/filesystem.js"
|
||||
import { Form } from "../src/form.js"
|
||||
import { Mcp } from "../src/mcp.js"
|
||||
import { Model } from "../src/model.js"
|
||||
import { Project } from "../src/project.js"
|
||||
|
|
@ -47,6 +48,33 @@ describe("contract hygiene", () => {
|
|||
).toEqual({ text: "completed" })
|
||||
})
|
||||
|
||||
test("forms require at least one field", () => {
|
||||
expect(() =>
|
||||
Schema.decodeUnknownSync(Form.Info)({
|
||||
id: Form.ID.create(),
|
||||
sessionID: "global",
|
||||
title: "Empty form",
|
||||
fields: [],
|
||||
}),
|
||||
).toThrow()
|
||||
expect(
|
||||
Schema.decodeUnknownSync(Form.Info)({
|
||||
id: Form.ID.create(),
|
||||
sessionID: "global",
|
||||
title: "External form",
|
||||
fields: [{ key: "authorization", type: "external", url: "https://example.com" }],
|
||||
}).fields,
|
||||
).toHaveLength(1)
|
||||
expect(() =>
|
||||
Schema.decodeUnknownSync(Form.Info)({
|
||||
id: Form.ID.create(),
|
||||
sessionID: "global",
|
||||
title: "External form",
|
||||
fields: [{ type: "external", url: "https://example.com" }],
|
||||
}),
|
||||
).toThrow()
|
||||
})
|
||||
|
||||
test("model defaults and provider overlays preserve public invariants", () => {
|
||||
const id = Model.ID.make("model")
|
||||
expect(Model.Info.empty(Provider.ID.make("provider"), id)).toMatchObject({ modelID: id, variants: [] })
|
||||
|
|
@ -69,6 +97,10 @@ describe("contract hygiene", () => {
|
|||
const identifiers = [
|
||||
Agent.Color,
|
||||
FileSystem.Submatch,
|
||||
Form.Field,
|
||||
Form.Fields,
|
||||
Form.Info,
|
||||
Form.ExternalField,
|
||||
Mcp.Resource,
|
||||
Mcp.ResourceTemplate,
|
||||
Mcp.ResourceCatalog,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue