Source HTTP API ID path patterns (#26623)
This commit is contained in:
@@ -105,11 +105,11 @@ Verification:
|
|||||||
|
|
||||||
Concrete first targets:
|
Concrete first targets:
|
||||||
|
|
||||||
- `sessionID`
|
- `[x]` `sessionID`
|
||||||
- `messageID`
|
- `[x]` `messageID`
|
||||||
- `partID`
|
- `[x]` `partID`
|
||||||
- `permissionID`
|
- `[x]` `permissionID`
|
||||||
- `ptyID`
|
- `[x]` `ptyID`
|
||||||
|
|
||||||
Leave ambiguous route-local `id` overrides for workspace routes until they are renamed or explicitly typed in endpoint params.
|
Leave ambiguous route-local `id` overrides for workspace routes until they are renamed or explicitly typed in endpoint params.
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import { Identifier } from "@/id/id"
|
|||||||
import { zod, ZodOverride } from "@opencode-ai/core/effect-zod"
|
import { zod, ZodOverride } from "@opencode-ai/core/effect-zod"
|
||||||
import { withStatics } from "@opencode-ai/core/schema"
|
import { withStatics } from "@opencode-ai/core/schema"
|
||||||
|
|
||||||
const ptyIdSchema = Schema.String.annotate({ [ZodOverride]: Identifier.schema("pty") }).pipe(Schema.brand("PtyID"))
|
const ptyIdSchema = Schema.String.check(Schema.isStartsWith("pty"))
|
||||||
|
.annotate({ [ZodOverride]: Identifier.schema("pty") })
|
||||||
|
.pipe(Schema.brand("PtyID"))
|
||||||
|
|
||||||
export type PtyID = typeof ptyIdSchema.Type
|
export type PtyID = typeof ptyIdSchema.Type
|
||||||
|
|
||||||
|
|||||||
@@ -69,14 +69,6 @@ const QueryParameterSchemas: Record<string, OpenApiSchema> = {
|
|||||||
"GET /api/session/{sessionID}/message limit": { type: "number" },
|
"GET /api/session/{sessionID}/message limit": { type: "number" },
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathParameterSchemas: Record<string, OpenApiSchema> = {
|
|
||||||
sessionID: { type: "string", pattern: "^ses.*" },
|
|
||||||
messageID: { type: "string", pattern: "^msg.*" },
|
|
||||||
partID: { type: "string", pattern: "^prt.*" },
|
|
||||||
permissionID: { type: "string", pattern: "^per.*" },
|
|
||||||
ptyID: { type: "string", pattern: "^pty.*" },
|
|
||||||
}
|
|
||||||
|
|
||||||
const LegacyComponentDescriptions: Record<string, string> = {
|
const LegacyComponentDescriptions: Record<string, string> = {
|
||||||
LogLevel: "Log level",
|
LogLevel: "Log level",
|
||||||
ServerConfig: "Server configuration for opencode serve and web commands",
|
ServerConfig: "Server configuration for opencode serve and web commands",
|
||||||
@@ -506,11 +498,8 @@ function normalizeParameter(param: OpenApiParameter, route: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function pathParameterSchema(route: string, name: string) {
|
function pathParameterSchema(route: string, name: string) {
|
||||||
if (name in PathParameterSchemas) return PathParameterSchemas[name]
|
|
||||||
if (name === "id" && route.startsWith("DELETE /experimental/workspace/")) return { type: "string", pattern: "^wrk.*" }
|
if (name === "id" && route.startsWith("DELETE /experimental/workspace/")) return { type: "string", pattern: "^wrk.*" }
|
||||||
if (name === "id" && route.startsWith("POST /experimental/workspace/")) return { type: "string", pattern: "^wrk.*" }
|
if (name === "id" && route.startsWith("POST /experimental/workspace/")) return { type: "string", pattern: "^wrk.*" }
|
||||||
if (name === "requestID" && route.startsWith("POST /permission/")) return { type: "string", pattern: "^per.*" }
|
|
||||||
if (name === "requestID" && route.startsWith("POST /question/")) return { type: "string", pattern: "^que.*" }
|
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,32 +4,44 @@ import { Identifier } from "@/id/id"
|
|||||||
import { zod, ZodOverride } from "@opencode-ai/core/effect-zod"
|
import { zod, ZodOverride } from "@opencode-ai/core/effect-zod"
|
||||||
import { withStatics } from "@opencode-ai/core/schema"
|
import { withStatics } from "@opencode-ai/core/schema"
|
||||||
|
|
||||||
export const SessionID = Schema.String.annotate({ [ZodOverride]: Identifier.schema("session") }).pipe(
|
export const SessionID = Schema.String.check(Schema.isStartsWith("ses"))
|
||||||
|
.annotate({
|
||||||
|
[ZodOverride]: Identifier.schema("session"),
|
||||||
|
})
|
||||||
|
.pipe(
|
||||||
Schema.brand("SessionID"),
|
Schema.brand("SessionID"),
|
||||||
withStatics((s) => ({
|
withStatics((s) => ({
|
||||||
descending: (id?: string) => s.make(Identifier.descending("session", id)),
|
descending: (id?: string) => s.make(Identifier.descending("session", id)),
|
||||||
zod: zod(s),
|
zod: zod(s),
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
|
|
||||||
export type SessionID = Schema.Schema.Type<typeof SessionID>
|
export type SessionID = Schema.Schema.Type<typeof SessionID>
|
||||||
|
|
||||||
export const MessageID = Schema.String.annotate({ [ZodOverride]: Identifier.schema("message") }).pipe(
|
export const MessageID = Schema.String.check(Schema.isStartsWith("msg"))
|
||||||
|
.annotate({
|
||||||
|
[ZodOverride]: Identifier.schema("message"),
|
||||||
|
})
|
||||||
|
.pipe(
|
||||||
Schema.brand("MessageID"),
|
Schema.brand("MessageID"),
|
||||||
withStatics((s) => ({
|
withStatics((s) => ({
|
||||||
ascending: (id?: string) => s.make(Identifier.ascending("message", id)),
|
ascending: (id?: string) => s.make(Identifier.ascending("message", id)),
|
||||||
zod: zod(s),
|
zod: zod(s),
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
|
|
||||||
export type MessageID = Schema.Schema.Type<typeof MessageID>
|
export type MessageID = Schema.Schema.Type<typeof MessageID>
|
||||||
|
|
||||||
export const PartID = Schema.String.annotate({ [ZodOverride]: Identifier.schema("part") }).pipe(
|
export const PartID = Schema.String.check(Schema.isStartsWith("prt"))
|
||||||
|
.annotate({
|
||||||
|
[ZodOverride]: Identifier.schema("part"),
|
||||||
|
})
|
||||||
|
.pipe(
|
||||||
Schema.brand("PartID"),
|
Schema.brand("PartID"),
|
||||||
withStatics((s) => ({
|
withStatics((s) => ({
|
||||||
ascending: (id?: string) => s.make(Identifier.ascending("part", id)),
|
ascending: (id?: string) => s.make(Identifier.ascending("part", id)),
|
||||||
zod: zod(s),
|
zod: zod(s),
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
|
|
||||||
export type PartID = Schema.Schema.Type<typeof PartID>
|
export type PartID = Schema.Schema.Type<typeof PartID>
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import { SessionID, MessageID, PartID } from "../../src/session/schema"
|
|||||||
function createTextPart(text: string): MessageV2.Part {
|
function createTextPart(text: string): MessageV2.Part {
|
||||||
return {
|
return {
|
||||||
id: PartID.ascending(),
|
id: PartID.ascending(),
|
||||||
sessionID: SessionID.make("s"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make("m"),
|
messageID: MessageID.make("msg_test"),
|
||||||
type: "text" as const,
|
type: "text" as const,
|
||||||
text,
|
text,
|
||||||
}
|
}
|
||||||
@@ -17,8 +17,8 @@ function createTextPart(text: string): MessageV2.Part {
|
|||||||
function createReasoningPart(text: string): MessageV2.Part {
|
function createReasoningPart(text: string): MessageV2.Part {
|
||||||
return {
|
return {
|
||||||
id: PartID.ascending(),
|
id: PartID.ascending(),
|
||||||
sessionID: SessionID.make("s"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make("m"),
|
messageID: MessageID.make("msg_test"),
|
||||||
type: "reasoning" as const,
|
type: "reasoning" as const,
|
||||||
text,
|
text,
|
||||||
time: { start: 0 },
|
time: { start: 0 },
|
||||||
@@ -29,8 +29,8 @@ function createToolPart(tool: string, title: string, status: "completed" | "runn
|
|||||||
if (status === "completed") {
|
if (status === "completed") {
|
||||||
return {
|
return {
|
||||||
id: PartID.ascending(),
|
id: PartID.ascending(),
|
||||||
sessionID: SessionID.make("s"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make("m"),
|
messageID: MessageID.make("msg_test"),
|
||||||
type: "tool" as const,
|
type: "tool" as const,
|
||||||
callID: "c1",
|
callID: "c1",
|
||||||
tool,
|
tool,
|
||||||
@@ -46,8 +46,8 @@ function createToolPart(tool: string, title: string, status: "completed" | "runn
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
id: PartID.ascending(),
|
id: PartID.ascending(),
|
||||||
sessionID: SessionID.make("s"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make("m"),
|
messageID: MessageID.make("msg_test"),
|
||||||
type: "tool" as const,
|
type: "tool" as const,
|
||||||
callID: "c1",
|
callID: "c1",
|
||||||
tool,
|
tool,
|
||||||
@@ -62,8 +62,8 @@ function createToolPart(tool: string, title: string, status: "completed" | "runn
|
|||||||
function createStepStartPart(): MessageV2.Part {
|
function createStepStartPart(): MessageV2.Part {
|
||||||
return {
|
return {
|
||||||
id: PartID.ascending(),
|
id: PartID.ascending(),
|
||||||
sessionID: SessionID.make("s"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make("m"),
|
messageID: MessageID.make("msg_test"),
|
||||||
type: "step-start" as const,
|
type: "step-start" as const,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,8 +71,8 @@ function createStepStartPart(): MessageV2.Part {
|
|||||||
function createStepFinishPart(): MessageV2.Part {
|
function createStepFinishPart(): MessageV2.Part {
|
||||||
return {
|
return {
|
||||||
id: PartID.ascending(),
|
id: PartID.ascending(),
|
||||||
sessionID: SessionID.make("s"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make("m"),
|
messageID: MessageID.make("msg_test"),
|
||||||
type: "step-finish" as const,
|
type: "step-finish" as const,
|
||||||
reason: "done",
|
reason: "done",
|
||||||
cost: 0,
|
cost: 0,
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ function run<A>(fn: (svc: Project.Interface) => Effect.Effect<A>) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function uid() {
|
function legacySessionID() {
|
||||||
return SessionID.make(crypto.randomUUID())
|
// Global-session migration covers persisted IDs from before prefixed session IDs.
|
||||||
|
return crypto.randomUUID() as SessionID
|
||||||
}
|
}
|
||||||
|
|
||||||
function seed(opts: { id: SessionID; dir: string; project: ProjectID }) {
|
function seed(opts: { id: SessionID; dir: string; project: ProjectID }) {
|
||||||
@@ -73,7 +74,7 @@ describe("migrateFromGlobal", () => {
|
|||||||
expect(pre.id).toBe(ProjectID.global)
|
expect(pre.id).toBe(ProjectID.global)
|
||||||
|
|
||||||
// 2. Seed a session under "global" with matching directory
|
// 2. Seed a session under "global" with matching directory
|
||||||
const id = uid()
|
const id = legacySessionID()
|
||||||
seed({ id, dir: tmp.path, project: ProjectID.global })
|
seed({ id, dir: tmp.path, project: ProjectID.global })
|
||||||
|
|
||||||
// 3. Make a commit so the project gets a real ID
|
// 3. Make a commit so the project gets a real ID
|
||||||
@@ -100,7 +101,7 @@ describe("migrateFromGlobal", () => {
|
|||||||
// 3. Seed a session under "global" with matching directory.
|
// 3. Seed a session under "global" with matching directory.
|
||||||
// This simulates a session created before git init that wasn't
|
// This simulates a session created before git init that wasn't
|
||||||
// present when the real project row was first created.
|
// present when the real project row was first created.
|
||||||
const id = uid()
|
const id = legacySessionID()
|
||||||
seed({ id, dir: tmp.path, project: ProjectID.global })
|
seed({ id, dir: tmp.path, project: ProjectID.global })
|
||||||
|
|
||||||
// 4. Call fromDirectory again — project row already exists,
|
// 4. Call fromDirectory again — project row already exists,
|
||||||
@@ -121,7 +122,7 @@ describe("migrateFromGlobal", () => {
|
|||||||
|
|
||||||
// Legacy sessions may lack a directory value.
|
// Legacy sessions may lack a directory value.
|
||||||
// Without a matching origin directory, they should remain global.
|
// Without a matching origin directory, they should remain global.
|
||||||
const id = uid()
|
const id = legacySessionID()
|
||||||
seed({ id, dir: "", project: ProjectID.global })
|
seed({ id, dir: "", project: ProjectID.global })
|
||||||
|
|
||||||
await run((svc) => svc.fromDirectory(tmp.path))
|
await run((svc) => svc.fromDirectory(tmp.path))
|
||||||
@@ -139,7 +140,7 @@ describe("migrateFromGlobal", () => {
|
|||||||
ensureGlobal()
|
ensureGlobal()
|
||||||
|
|
||||||
// Seed a session under "global" but for a DIFFERENT directory
|
// Seed a session under "global" but for a DIFFERENT directory
|
||||||
const id = uid()
|
const id = legacySessionID()
|
||||||
seed({ id, dir: "/some/other/dir", project: ProjectID.global })
|
seed({ id, dir: "/some/other/dir", project: ProjectID.global })
|
||||||
|
|
||||||
await run((svc) => svc.fromDirectory(tmp.path))
|
await run((svc) => svc.fromDirectory(tmp.path))
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
MessagesQuery,
|
MessagesQuery,
|
||||||
SessionPaths,
|
SessionPaths,
|
||||||
} from "../../src/server/routes/instance/httpapi/groups/session"
|
} from "../../src/server/routes/instance/httpapi/groups/session"
|
||||||
|
import { PtyPaths } from "../../src/server/routes/instance/httpapi/groups/pty"
|
||||||
import { MessagesQuery as V2MessagesQuery } from "../../src/server/routes/instance/httpapi/groups/v2/message"
|
import { MessagesQuery as V2MessagesQuery } from "../../src/server/routes/instance/httpapi/groups/v2/message"
|
||||||
import { SessionsQuery as V2SessionsQuery } from "../../src/server/routes/instance/httpapi/groups/v2/session"
|
import { SessionsQuery as V2SessionsQuery } from "../../src/server/routes/instance/httpapi/groups/v2/session"
|
||||||
import { QueryBoolean } from "../../src/server/routes/instance/httpapi/groups/query"
|
import { QueryBoolean } from "../../src/server/routes/instance/httpapi/groups/query"
|
||||||
@@ -33,7 +34,12 @@ const originalWorkspaces = Flag.OPENCODE_EXPERIMENTAL_WORKSPACES
|
|||||||
|
|
||||||
type Method = "get" | "post" | "put" | "delete" | "patch"
|
type Method = "get" | "post" | "put" | "delete" | "patch"
|
||||||
type QuerySchema = { readonly fields: Record<string, unknown> }
|
type QuerySchema = { readonly fields: Record<string, unknown> }
|
||||||
type OpenApiSchema = { readonly maximum?: number; readonly minimum?: number; readonly type?: string }
|
type OpenApiSchema = {
|
||||||
|
readonly maximum?: number
|
||||||
|
readonly minimum?: number
|
||||||
|
readonly pattern?: string
|
||||||
|
readonly type?: string
|
||||||
|
}
|
||||||
type OpenApiParameter = { readonly name: string; readonly in: string; readonly schema?: OpenApiSchema }
|
type OpenApiParameter = { readonly name: string; readonly in: string; readonly schema?: OpenApiSchema }
|
||||||
type OpenApiOperation = { readonly parameters?: readonly OpenApiParameter[] }
|
type OpenApiOperation = { readonly parameters?: readonly OpenApiParameter[] }
|
||||||
|
|
||||||
@@ -68,6 +74,16 @@ const numericSdkQueryParams = [
|
|||||||
{ method: "get", path: "/api/session/:sessionID/message", name: "limit", schema: { type: "number" } },
|
{ method: "get", path: "/api/session/:sessionID/message", name: "limit", schema: { type: "number" } },
|
||||||
] satisfies Array<{ method: Method; path: string; name: string; schema: OpenApiSchema }>
|
] satisfies Array<{ method: Method; path: string; name: string; schema: OpenApiSchema }>
|
||||||
|
|
||||||
|
const pathParamPatterns = [
|
||||||
|
{ method: "get", path: SessionPaths.get, name: "sessionID", pattern: "^ses" },
|
||||||
|
{ method: "get", path: SessionPaths.message, name: "messageID", pattern: "^msg" },
|
||||||
|
{ method: "patch", path: SessionPaths.updatePart, name: "partID", pattern: "^prt" },
|
||||||
|
{ method: "post", path: SessionPaths.permissions, name: "permissionID", pattern: "^per" },
|
||||||
|
{ method: "post", path: "/permission/:requestID/reply", name: "requestID", pattern: "^per" },
|
||||||
|
{ method: "post", path: "/question/:requestID/reply", name: "requestID", pattern: "^que" },
|
||||||
|
{ method: "put", path: PtyPaths.update, name: "ptyID", pattern: "^pty" },
|
||||||
|
] satisfies Array<{ method: Method; path: string; name: string; pattern: string }>
|
||||||
|
|
||||||
function app() {
|
function app() {
|
||||||
return Server.Default().app
|
return Server.Default().app
|
||||||
}
|
}
|
||||||
@@ -98,6 +114,10 @@ function queryParameter(operation: OpenApiOperation | undefined, name: string) {
|
|||||||
return (operation?.parameters ?? []).find((param) => param.in === "query" && param.name === name)
|
return (operation?.parameters ?? []).find((param) => param.in === "query" && param.name === name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pathParameter(operation: OpenApiOperation | undefined, name: string) {
|
||||||
|
return (operation?.parameters ?? []).find((param) => param.in === "path" && param.name === name)
|
||||||
|
}
|
||||||
|
|
||||||
function assertAdvertisedQueryParamsAreRuntimeFields(input: {
|
function assertAdvertisedQueryParamsAreRuntimeFields(input: {
|
||||||
readonly method: Method
|
readonly method: Method
|
||||||
readonly operation: OpenApiOperation | undefined
|
readonly operation: OpenApiOperation | undefined
|
||||||
@@ -173,6 +193,19 @@ describe("httpapi query schema drift", () => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it.effect(
|
||||||
|
"OpenAPI path parameter patterns come from runtime schemas",
|
||||||
|
Effect.sync(() => {
|
||||||
|
const spec = OpenApi.fromApi(PublicApi)
|
||||||
|
for (const expected of pathParamPatterns) {
|
||||||
|
expect(
|
||||||
|
pathParameter(spec.paths[openApiPath(expected.path)]?.[expected.method], expected.name)?.schema,
|
||||||
|
`${expected.method.toUpperCase()} ${expected.path} ${expected.name}`,
|
||||||
|
).toEqual({ type: "string", pattern: expected.pattern })
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
it.effect(
|
it.effect(
|
||||||
"drift assertion catches spec-only workspace query params",
|
"drift assertion catches spec-only workspace query params",
|
||||||
Effect.sync(() => {
|
Effect.sync(() => {
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ describe("HttpApi UI fallback", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test("keeps matched API routes ahead of the UI fallback", async () => {
|
test("keeps matched API routes ahead of the UI fallback", async () => {
|
||||||
const response = await Server.Default().app.request("/session/nope")
|
const response = await Server.Default().app.request("/session/ses_nope")
|
||||||
|
|
||||||
expect(response.status).toBe(404)
|
expect(response.status).toBe(404)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ const tmpWithFiles = (files: Record<string, string>) =>
|
|||||||
|
|
||||||
function loaded(filepath: string): MessageV2.WithParts[] {
|
function loaded(filepath: string): MessageV2.WithParts[] {
|
||||||
const sessionID = SessionID.make("session-loaded-1")
|
const sessionID = SessionID.make("session-loaded-1")
|
||||||
const messageID = MessageID.make("message-loaded-1")
|
const messageID = MessageID.make("msg_message-loaded-1")
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -78,7 +78,7 @@ function loaded(filepath: string): MessageV2.WithParts[] {
|
|||||||
},
|
},
|
||||||
parts: [
|
parts: [
|
||||||
{
|
{
|
||||||
id: PartID.make("part-loaded-1"),
|
id: PartID.make("prt_part-loaded-1"),
|
||||||
messageID,
|
messageID,
|
||||||
sessionID,
|
sessionID,
|
||||||
type: "tool",
|
type: "tool",
|
||||||
@@ -106,7 +106,7 @@ describe("Instruction.resolve", () => {
|
|||||||
const system = yield* svc.systemPaths()
|
const system = yield* svc.systemPaths()
|
||||||
expect(system.has(path.join(dir, "AGENTS.md"))).toBe(true)
|
expect(system.has(path.join(dir, "AGENTS.md"))).toBe(true)
|
||||||
|
|
||||||
const results = yield* svc.resolve([], path.join(dir, "src", "file.ts"), MessageID.make("message-test-1"))
|
const results = yield* svc.resolve([], path.join(dir, "src", "file.ts"), MessageID.make("msg_message-test-1"))
|
||||||
expect(results).toEqual([])
|
expect(results).toEqual([])
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@@ -122,7 +122,7 @@ describe("Instruction.resolve", () => {
|
|||||||
const results = yield* svc.resolve(
|
const results = yield* svc.resolve(
|
||||||
[],
|
[],
|
||||||
path.join(dir, "subdir", "nested", "file.ts"),
|
path.join(dir, "subdir", "nested", "file.ts"),
|
||||||
MessageID.make("message-test-2"),
|
MessageID.make("msg_message-test-2"),
|
||||||
)
|
)
|
||||||
expect(results.length).toBe(1)
|
expect(results.length).toBe(1)
|
||||||
expect(results[0].filepath).toBe(path.join(dir, "subdir", "AGENTS.md"))
|
expect(results[0].filepath).toBe(path.join(dir, "subdir", "AGENTS.md"))
|
||||||
@@ -138,7 +138,7 @@ describe("Instruction.resolve", () => {
|
|||||||
const system = yield* svc.systemPaths()
|
const system = yield* svc.systemPaths()
|
||||||
expect(system.has(filepath)).toBe(false)
|
expect(system.has(filepath)).toBe(false)
|
||||||
|
|
||||||
const results = yield* svc.resolve([], filepath, MessageID.make("message-test-3"))
|
const results = yield* svc.resolve([], filepath, MessageID.make("msg_message-test-3"))
|
||||||
expect(results).toEqual([])
|
expect(results).toEqual([])
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@@ -149,7 +149,7 @@ describe("Instruction.resolve", () => {
|
|||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const svc = yield* Instruction.Service
|
const svc = yield* Instruction.Service
|
||||||
const filepath = path.join(dir, "subdir", "nested", "file.ts")
|
const filepath = path.join(dir, "subdir", "nested", "file.ts")
|
||||||
const id = MessageID.make("message-claim-1")
|
const id = MessageID.make("msg_message-claim-1")
|
||||||
|
|
||||||
const first = yield* svc.resolve([], filepath, id)
|
const first = yield* svc.resolve([], filepath, id)
|
||||||
const second = yield* svc.resolve([], filepath, id)
|
const second = yield* svc.resolve([], filepath, id)
|
||||||
@@ -166,7 +166,7 @@ describe("Instruction.resolve", () => {
|
|||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const svc = yield* Instruction.Service
|
const svc = yield* Instruction.Service
|
||||||
const filepath = path.join(dir, "subdir", "nested", "file.ts")
|
const filepath = path.join(dir, "subdir", "nested", "file.ts")
|
||||||
const id = MessageID.make("message-claim-2")
|
const id = MessageID.make("msg_message-claim-2")
|
||||||
|
|
||||||
const first = yield* svc.resolve([], filepath, id)
|
const first = yield* svc.resolve([], filepath, id)
|
||||||
yield* svc.clear(id)
|
yield* svc.clear(id)
|
||||||
@@ -185,7 +185,7 @@ describe("Instruction.resolve", () => {
|
|||||||
const svc = yield* Instruction.Service
|
const svc = yield* Instruction.Service
|
||||||
const agents = path.join(dir, "subdir", "AGENTS.md")
|
const agents = path.join(dir, "subdir", "AGENTS.md")
|
||||||
const filepath = path.join(dir, "subdir", "nested", "file.ts")
|
const filepath = path.join(dir, "subdir", "nested", "file.ts")
|
||||||
const id = MessageID.make("message-claim-3")
|
const id = MessageID.make("msg_message-claim-3")
|
||||||
|
|
||||||
const results = yield* svc.resolve(loaded(agents), filepath, id)
|
const results = yield* svc.resolve(loaded(agents), filepath, id)
|
||||||
expect(results).toEqual([])
|
expect(results).toEqual([])
|
||||||
|
|||||||
@@ -354,7 +354,7 @@ describe("session.llm.stream", () => {
|
|||||||
} satisfies Agent.Info
|
} satisfies Agent.Info
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
id: MessageID.make("user-1"),
|
id: MessageID.make("msg_user-1"),
|
||||||
sessionID,
|
sessionID,
|
||||||
role: "user",
|
role: "user",
|
||||||
time: { created: Date.now() },
|
time: { created: Date.now() },
|
||||||
@@ -438,7 +438,7 @@ describe("session.llm.stream", () => {
|
|||||||
permission: [{ permission: "*", pattern: "*", action: "allow" }],
|
permission: [{ permission: "*", pattern: "*", action: "allow" }],
|
||||||
} satisfies Agent.Info
|
} satisfies Agent.Info
|
||||||
const user = {
|
const user = {
|
||||||
id: MessageID.make("user-service-abort"),
|
id: MessageID.make("msg_user-service-abort"),
|
||||||
sessionID,
|
sessionID,
|
||||||
role: "user",
|
role: "user",
|
||||||
time: { created: Date.now() },
|
time: { created: Date.now() },
|
||||||
@@ -529,7 +529,7 @@ describe("session.llm.stream", () => {
|
|||||||
} satisfies Agent.Info
|
} satisfies Agent.Info
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
id: MessageID.make("user-tools"),
|
id: MessageID.make("msg_user-tools"),
|
||||||
sessionID,
|
sessionID,
|
||||||
role: "user",
|
role: "user",
|
||||||
time: { created: Date.now() },
|
time: { created: Date.now() },
|
||||||
@@ -644,7 +644,7 @@ describe("session.llm.stream", () => {
|
|||||||
} satisfies Agent.Info
|
} satisfies Agent.Info
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
id: MessageID.make("user-2"),
|
id: MessageID.make("msg_user-2"),
|
||||||
sessionID,
|
sessionID,
|
||||||
role: "user",
|
role: "user",
|
||||||
time: { created: Date.now() },
|
time: { created: Date.now() },
|
||||||
@@ -759,7 +759,7 @@ describe("session.llm.stream", () => {
|
|||||||
} satisfies Agent.Info
|
} satisfies Agent.Info
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
id: MessageID.make("user-data-url"),
|
id: MessageID.make("msg_user-data-url"),
|
||||||
sessionID,
|
sessionID,
|
||||||
role: "user",
|
role: "user",
|
||||||
time: { created: Date.now() },
|
time: { created: Date.now() },
|
||||||
@@ -880,7 +880,7 @@ describe("session.llm.stream", () => {
|
|||||||
} satisfies Agent.Info
|
} satisfies Agent.Info
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
id: MessageID.make("user-3"),
|
id: MessageID.make("msg_user-3"),
|
||||||
sessionID,
|
sessionID,
|
||||||
role: "user",
|
role: "user",
|
||||||
time: { created: Date.now() },
|
time: { created: Date.now() },
|
||||||
@@ -995,7 +995,7 @@ describe("session.llm.stream", () => {
|
|||||||
permission: [{ permission: "*", pattern: "*", action: "allow" }],
|
permission: [{ permission: "*", pattern: "*", action: "allow" }],
|
||||||
} satisfies Agent.Info
|
} satisfies Agent.Info
|
||||||
const user = {
|
const user = {
|
||||||
id: MessageID.make("user-anthropic-tools"),
|
id: MessageID.make("msg_user-anthropic-tools"),
|
||||||
sessionID,
|
sessionID,
|
||||||
role: "user",
|
role: "user",
|
||||||
time: { created: Date.now() },
|
time: { created: Date.now() },
|
||||||
@@ -1239,7 +1239,7 @@ describe("session.llm.stream", () => {
|
|||||||
} satisfies Agent.Info
|
} satisfies Agent.Info
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
id: MessageID.make("user-4"),
|
id: MessageID.make("msg_user-4"),
|
||||||
sessionID,
|
sessionID,
|
||||||
role: "user",
|
role: "user",
|
||||||
time: { created: Date.now() },
|
time: { created: Date.now() },
|
||||||
|
|||||||
@@ -102,9 +102,9 @@ function assistantInfo(
|
|||||||
|
|
||||||
function basePart(messageID: string, id: string) {
|
function basePart(messageID: string, id: string) {
|
||||||
return {
|
return {
|
||||||
id: PartID.make(id),
|
id: PartID.make(id.startsWith("prt") ? id : `prt_${id}`),
|
||||||
sessionID,
|
sessionID,
|
||||||
messageID: MessageID.make(messageID),
|
messageID: MessageID.make(messageID.startsWith("msg") ? messageID : `msg_${messageID}`),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const runtime = ManagedRuntime.make(
|
|||||||
|
|
||||||
const baseCtx = {
|
const baseCtx = {
|
||||||
sessionID: SessionID.make("ses_test"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make(""),
|
messageID: MessageID.make("msg_test"),
|
||||||
callID: "",
|
callID: "",
|
||||||
agent: "build",
|
agent: "build",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { SessionID, MessageID } from "../../src/session/schema"
|
|||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
sessionID: SessionID.make("ses_test-edit-session"),
|
sessionID: SessionID.make("ses_test-edit-session"),
|
||||||
messageID: MessageID.make(""),
|
messageID: MessageID.make("msg_test"),
|
||||||
callID: "",
|
callID: "",
|
||||||
agent: "build",
|
agent: "build",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { SessionID, MessageID } from "../../src/session/schema"
|
|||||||
|
|
||||||
const baseCtx: Omit<Tool.Context, "ask"> = {
|
const baseCtx: Omit<Tool.Context, "ask"> = {
|
||||||
sessionID: SessionID.make("ses_test"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make(""),
|
messageID: MessageID.make("msg_test"),
|
||||||
callID: "",
|
callID: "",
|
||||||
agent: "build",
|
agent: "build",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const it = testEffect(
|
|||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
sessionID: SessionID.make("ses_test"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make(""),
|
messageID: MessageID.make("msg_test"),
|
||||||
callID: "",
|
callID: "",
|
||||||
agent: "build",
|
agent: "build",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const it = testEffect(
|
|||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
sessionID: SessionID.make("ses_test"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make(""),
|
messageID: MessageID.make("msg_test"),
|
||||||
callID: "",
|
callID: "",
|
||||||
agent: "build",
|
agent: "build",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ afterEach(async () => {
|
|||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
sessionID: SessionID.make("ses_test"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make(""),
|
messageID: MessageID.make("msg_test"),
|
||||||
callID: "",
|
callID: "",
|
||||||
agent: "build",
|
agent: "build",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { testEffect } from "../lib/effect"
|
|||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
sessionID: SessionID.make("ses_test-session"),
|
sessionID: SessionID.make("ses_test-session"),
|
||||||
messageID: MessageID.make("test-message"),
|
messageID: MessageID.make("msg_test-message"),
|
||||||
callID: "test-call",
|
callID: "test-call",
|
||||||
agent: "test-agent",
|
agent: "test-agent",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ afterEach(async () => {
|
|||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
sessionID: SessionID.make("ses_test"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make(""),
|
messageID: MessageID.make("msg_test"),
|
||||||
callID: "",
|
callID: "",
|
||||||
agent: "build",
|
agent: "build",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ afterEach(async () => {
|
|||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
sessionID: SessionID.make("ses_test"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make(""),
|
messageID: MessageID.make("msg_test"),
|
||||||
callID: "",
|
callID: "",
|
||||||
agent: "scout",
|
agent: "scout",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ afterEach(async () => {
|
|||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
sessionID: SessionID.make("ses_test"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make(""),
|
messageID: MessageID.make("msg_test"),
|
||||||
callID: "",
|
callID: "",
|
||||||
agent: "scout",
|
agent: "scout",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const initShell = initBash
|
|||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
sessionID: SessionID.make("ses_test"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make(""),
|
messageID: MessageID.make("msg_test"),
|
||||||
callID: "",
|
callID: "",
|
||||||
agent: "build",
|
agent: "build",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { testEffect } from "../lib/effect"
|
|||||||
|
|
||||||
const baseCtx: Omit<Tool.Context, "ask"> = {
|
const baseCtx: Omit<Tool.Context, "ask"> = {
|
||||||
sessionID: SessionID.make("ses_test"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make(""),
|
messageID: MessageID.make("msg_test"),
|
||||||
callID: "",
|
callID: "",
|
||||||
agent: "build",
|
agent: "build",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const projectRoot = path.join(import.meta.dir, "../..")
|
|||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
sessionID: SessionID.make("ses_test"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
messageID: MessageID.make("message"),
|
messageID: MessageID.make("msg_message"),
|
||||||
callID: "",
|
callID: "",
|
||||||
agent: "build",
|
agent: "build",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { testEffect } from "../lib/effect"
|
|||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
sessionID: SessionID.make("ses_test-write-session"),
|
sessionID: SessionID.make("ses_test-write-session"),
|
||||||
messageID: MessageID.make(""),
|
messageID: MessageID.make("msg_test"),
|
||||||
callID: "",
|
callID: "",
|
||||||
agent: "build",
|
agent: "build",
|
||||||
abort: AbortSignal.any([]),
|
abort: AbortSignal.any([]),
|
||||||
|
|||||||
Reference in New Issue
Block a user