refactor(core): rename system context to instructions (#35583)
This commit is contained in:
parent
1a52e1118e
commit
91f1815732
62 changed files with 1482 additions and 1005 deletions
|
|
@ -2350,12 +2350,12 @@
|
|||
"summary": "Get session context"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/context-entry": {
|
||||
"/api/session/{sessionID}/instructions/entries": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"sessions"
|
||||
],
|
||||
"operationId": "v2.session.context.entry.list",
|
||||
"operationId": "v2.session.instructions.entry.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
|
|
@ -2383,7 +2383,7 @@
|
|||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/SessionContextEntry.Info"
|
||||
"$ref": "#/components/schemas/InstructionEntry.Info"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -2433,16 +2433,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"description": "List API-managed context entries attached to the session's system context.",
|
||||
"summary": "List context entries"
|
||||
"description": "List API-managed instruction entries attached to the session.",
|
||||
"summary": "List instruction entries"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/context-entry/{key}": {
|
||||
"/api/session/{sessionID}/instructions/entries/{key}": {
|
||||
"put": {
|
||||
"tags": [
|
||||
"sessions"
|
||||
],
|
||||
"operationId": "v2.session.context.entry.put",
|
||||
"operationId": "v2.session.instructions.entry.put",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
|
|
@ -2461,7 +2461,7 @@
|
|||
"name": "key",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SessionContextEntry.Key"
|
||||
"$ref": "#/components/schemas/InstructionEntry.Key"
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
|
|
@ -2509,8 +2509,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"description": "Attach or replace one durable context entry. The value is rendered into the session's system context; changes announce as updates at the next turn boundary.",
|
||||
"summary": "Put context entry",
|
||||
"description": "Attach or replace one durable instruction entry. Changes announce as updates at the next step boundary.",
|
||||
"summary": "Put instruction entry",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
|
|
@ -2533,7 +2533,7 @@
|
|||
"tags": [
|
||||
"sessions"
|
||||
],
|
||||
"operationId": "v2.session.context.entry.remove",
|
||||
"operationId": "v2.session.instructions.entry.remove",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
|
|
@ -2552,7 +2552,7 @@
|
|||
"name": "key",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SessionContextEntry.Key"
|
||||
"$ref": "#/components/schemas/InstructionEntry.Key"
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
|
|
@ -2600,8 +2600,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"description": "Remove one context entry; the removal is announced to the model at the next turn boundary.",
|
||||
"summary": "Remove context entry"
|
||||
"description": "Remove one instruction entry; the removal is announced to the model at the next step boundary.",
|
||||
"summary": "Remove instruction entry"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/log": {
|
||||
|
|
@ -11692,7 +11692,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"SessionContextEntry.Key": {
|
||||
"InstructionEntry.Key": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
|
|
@ -11701,11 +11701,11 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"SessionContextEntry.Info": {
|
||||
"InstructionEntry.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"$ref": "#/components/schemas/SessionContextEntry.Key"
|
||||
"$ref": "#/components/schemas/InstructionEntry.Key"
|
||||
},
|
||||
"value": {}
|
||||
},
|
||||
|
|
@ -12385,7 +12385,7 @@
|
|||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.context.updated": {
|
||||
"session.next.instructions.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
|
|
@ -12402,7 +12402,7 @@
|
|||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"session.next.context.updated"
|
||||
"session.next.instructions.updated"
|
||||
]
|
||||
},
|
||||
"durable": {
|
||||
|
|
@ -14917,7 +14917,7 @@
|
|||
"$ref": "#/components/schemas/session.next.prompt.admitted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.context.updated"
|
||||
"$ref": "#/components/schemas/session.next.instructions.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.synthetic"
|
||||
|
|
@ -26060,7 +26060,7 @@
|
|||
"$ref": "#/components/schemas/session.next.execution.settled"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.context.updated"
|
||||
"$ref": "#/components/schemas/session.next.instructions.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.synthetic"
|
||||
|
|
|
|||
|
|
@ -54,7 +54,9 @@ const json = (value: unknown, status = 200) =>
|
|||
|
||||
const singleOperation = (operation: Record<string, unknown>, method = "get"): Document => ({
|
||||
openapi: "3.1.0",
|
||||
paths: { "/test": { [method]: { operationId: "test", responses: { 200: { description: "Success" } }, ...operation } } },
|
||||
paths: {
|
||||
"/test": { [method]: { operationId: "test", responses: { 200: { description: "Success" } }, ...operation } },
|
||||
},
|
||||
})
|
||||
|
||||
describe("OpenAPI.fromSpec", () => {
|
||||
|
|
@ -94,7 +96,12 @@ describe("OpenAPI.fromSpec", () => {
|
|||
const remove = toolAt(api.tools, "users.remove")
|
||||
|
||||
expect(api.skipped).toEqual([])
|
||||
if (!Tool.isDefinition(get) || !Tool.isDefinition(create) || !Tool.isDefinition(search) || !Tool.isDefinition(remove)) {
|
||||
if (
|
||||
!Tool.isDefinition(get) ||
|
||||
!Tool.isDefinition(create) ||
|
||||
!Tool.isDefinition(search) ||
|
||||
!Tool.isDefinition(remove)
|
||||
) {
|
||||
throw new Error("happy-path fixture did not generate every operation")
|
||||
}
|
||||
expect(inputTypeScript(get)).toBe(
|
||||
|
|
@ -110,7 +117,8 @@ describe("OpenAPI.fromSpec", () => {
|
|||
|
||||
const result = await Effect.runPromise(
|
||||
CodeMode.make({ tools: { api: api.tools } })
|
||||
.execute(`
|
||||
.execute(
|
||||
`
|
||||
const user = await tools.api.users.get({
|
||||
userId: "user-1",
|
||||
include: ["profile", "permissions"],
|
||||
|
|
@ -128,7 +136,8 @@ describe("OpenAPI.fromSpec", () => {
|
|||
})
|
||||
const removed = await tools.api.users.remove({ userId: "user-1" })
|
||||
return { user, created, summary, removed }
|
||||
`)
|
||||
`,
|
||||
)
|
||||
.pipe(Effect.provide(client.layer)),
|
||||
)
|
||||
|
||||
|
|
@ -196,11 +205,11 @@ describe("OpenAPI.fromSpec", () => {
|
|||
if (!Tool.isDefinition(switchAgent)) throw new Error("v2.session.switchAgent was not generated")
|
||||
expect(inputTypeScript(switchAgent)).toBe("{ sessionID: string; agent: string }")
|
||||
|
||||
const contextEntryPut = toolAt(result.tools, "v2.session.contextEntry.put")
|
||||
expect(Tool.isDefinition(contextEntryPut)).toBe(true)
|
||||
if (!Tool.isDefinition(contextEntryPut)) throw new Error("v2.session.contextEntry.put was not generated")
|
||||
expect(inputTypeScript(contextEntryPut)).toBe("{ sessionID: string; key: string; value: unknown }")
|
||||
expect(toolAt(result.tools, "v2_session_context_entry_put_2")).toBeUndefined()
|
||||
const instructionPut = toolAt(result.tools, "v2.session.instructions.entry.put")
|
||||
expect(Tool.isDefinition(instructionPut)).toBe(true)
|
||||
if (!Tool.isDefinition(instructionPut)) throw new Error("v2.session.instructions.entry.put was not generated")
|
||||
expect(inputTypeScript(instructionPut)).toBe("{ sessionID: string; key: string; value: unknown }")
|
||||
expect(toolAt(result.tools, "v2_session_instructions_entry_put_2")).toBeUndefined()
|
||||
expect(toolAt(result.tools, "v2.pty.connect")).toBeUndefined()
|
||||
expect(toolAt(result.tools, "v2.session.log")).toBeUndefined()
|
||||
expect(toolAt(result.tools, "v2.event.subscribe")).toBeUndefined()
|
||||
|
|
@ -481,9 +490,9 @@ describe("OpenAPI.fromSpec", () => {
|
|||
expect(url.searchParams.get("nullable")).toBe("null")
|
||||
expect(url.searchParams.get("constructor")).toBe("safe")
|
||||
expect(client.requests[0]!.headers.meta).toBe("a=b,c=d")
|
||||
await expect(
|
||||
Effect.runPromise(tool.run({ keys: [undefined] }).pipe(Effect.provide(client.layer))),
|
||||
).rejects.toThrow("unsupported nested value")
|
||||
await expect(Effect.runPromise(tool.run({ keys: [undefined] }).pipe(Effect.provide(client.layer)))).rejects.toThrow(
|
||||
"unsupported nested value",
|
||||
)
|
||||
})
|
||||
|
||||
test("skips unsupported parameter encodings and malformed security", () => {
|
||||
|
|
@ -585,7 +594,10 @@ describe("OpenAPI.fromSpec", () => {
|
|||
|
||||
test("applies authentication carriers without prototype or collision loss", async () => {
|
||||
const client = recordingClient(() => json({ ok: true }))
|
||||
const authenticated = (security: ReadonlyArray<Record<string, ReadonlyArray<string>>>, schemes: Record<string, unknown>) =>
|
||||
const authenticated = (
|
||||
security: ReadonlyArray<Record<string, ReadonlyArray<string>>>,
|
||||
schemes: Record<string, unknown>,
|
||||
) =>
|
||||
OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: { ...singleOperation({}), security, components: { securitySchemes: schemes } },
|
||||
|
|
@ -601,13 +613,10 @@ describe("OpenAPI.fromSpec", () => {
|
|||
expect(new URL(client.requests[0]!.url).searchParams.get("__proto__")).toBe("secret")
|
||||
|
||||
const duplicate = toolAt(
|
||||
authenticated(
|
||||
[{ first: [], second: [] }],
|
||||
{
|
||||
first: { type: "apiKey", in: "header", name: "x-key" },
|
||||
second: { type: "apiKey", in: "header", name: "x-key" },
|
||||
},
|
||||
).tools,
|
||||
authenticated([{ first: [], second: [] }], {
|
||||
first: { type: "apiKey", in: "header", name: "x-key" },
|
||||
second: { type: "apiKey", in: "header", name: "x-key" },
|
||||
}).tools,
|
||||
"test",
|
||||
)
|
||||
if (!Tool.isDefinition(duplicate)) throw new Error("duplicate auth tool was not generated")
|
||||
|
|
@ -632,8 +641,7 @@ describe("OpenAPI.fromSpec", () => {
|
|||
},
|
||||
},
|
||||
auth: {
|
||||
resolve: ({ name }) =>
|
||||
Effect.succeed(name === "bearer" ? { type: "bearer", token: "secret" } : undefined),
|
||||
resolve: ({ name }) => Effect.succeed(name === "bearer" ? { type: "bearer", token: "secret" } : undefined),
|
||||
},
|
||||
})
|
||||
const alternativeTool = toolAt(alternative.tools, "test")
|
||||
|
|
@ -765,9 +773,7 @@ describe("OpenAPI.fromSpec", () => {
|
|||
const oversized = recordingClient(
|
||||
() => new Response(null, { headers: { "content-length": String(50 * 1024 * 1024 + 1) } }),
|
||||
)
|
||||
const malformed = recordingClient(
|
||||
() => new Response("{", { headers: { "content-type": "application/json" } }),
|
||||
)
|
||||
const malformed = recordingClient(() => new Response("{", { headers: { "content-type": "application/json" } }))
|
||||
const chunked = recordingClient(() => new Response(new Uint8Array(50 * 1024 * 1024 + 1)))
|
||||
|
||||
await expect(Effect.runPromise(tool.run({}).pipe(Effect.provide(oversized.layer)))).rejects.toThrow(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue