mirror of
https://gitee.com/zhangsken/opencode.git
synced 2026-10-16 10:30:01 +08:00
refactor(session): consolidate mutable properties
This commit is contained in:
@@ -147,7 +147,7 @@ Review endpoints in document order. For each endpoint, select one disposition an
|
||||
| [x] 053 | `POST` | `/api/session/{sessionID}/fork` | `session.fork` | Change | Request now accepts optional branded `before` message ID; omission copies full history. |
|
||||
| [x] 054 | `POST` | `/api/session/{sessionID}/agent` | `session.switchAgent` | Keep | Subsequent-execution agent selection retained. |
|
||||
| [x] 055 | `POST` | `/api/session/{sessionID}/model` | `session.switchModel` | Keep | Subsequent-execution model and optional variant selection retained. |
|
||||
| [x] 056 | `PATCH` | `/api/session/{sessionID}` | `session.rename` | Change | Title-only rename now uses the session resource path. |
|
||||
| [x] 056 | `PATCH` | `/api/session/{sessionID}` | `session.update` | Change | General session patch now updates optional title and permissions. |
|
||||
| [x] 057 | `POST` | `/api/session/{sessionID}/move` | `session.move` | Change | Removed inaccurate local-change transfer claim; delivery behavior retained. |
|
||||
| [x] 058 | `POST` | `/api/session/{sessionID}/background` | `session.background` | Keep | Backgroundable foreground tools transition to background observation; idle requests remain no-ops. |
|
||||
|
||||
@@ -213,7 +213,7 @@ Review endpoints in document order. For each endpoint, select one disposition an
|
||||
| [x] 098 | `GET` | `/api/session/{sessionID}/permission` | `session.permission.list` | Keep | Pending session permission list retained. |
|
||||
| [x] 099 | `GET` | `/api/session/{sessionID}/permission/{requestID}` | `session.permission.get` | Keep | Specific pending permission read with ownership validation retained. |
|
||||
| [x] 100 | `POST` | `/api/session/{sessionID}/permission/{requestID}/reply` | `session.permission.reply` | Change | Renamed request field from `reply` to `decision`. |
|
||||
| [ ] 101 | `PUT` | `/api/session/{sessionID}/permission/rules` | `session.permission.rules` | | |
|
||||
| [x] 101 | — | — | — | Remove | Permission rules are updated through `session.update`. |
|
||||
|
||||
## Group 8: Filesystem, worktrees, and VCS
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ export function createHomeSessionsController(home: HomeController) {
|
||||
const next = title.trim()
|
||||
if (!next || next === sessionLabel(session)) return true
|
||||
return ctx.sdk.api.session
|
||||
.rename({ sessionID: session.id, title: next })
|
||||
.update({ sessionID: session.id, title: next })
|
||||
.then(() => {
|
||||
ctx.data.session.remember({ ...(ctx.data.session.get(session.id) ?? session), title: next })
|
||||
// Rename advances time.updated server-side; re-sync the canonical
|
||||
|
||||
@@ -149,7 +149,7 @@ export function createTimelineController(input: { session: TimelineSessionSource
|
||||
if (!next || next === (titleLabel() ?? "")) return true
|
||||
setPending("rename", true)
|
||||
const success = await serverSDK.api.session
|
||||
.rename({ sessionID: id, title: next })
|
||||
.update({ sessionID: id, title: next })
|
||||
.then(() => true)
|
||||
.catch((error) => {
|
||||
showToast({ title: language.t("common.requestFailed"), description: errorMessage(error) })
|
||||
|
||||
@@ -116,7 +116,7 @@ function SessionTabEntry(props: {
|
||||
|
||||
ctx.data.session.remember({ ...value, title })
|
||||
try {
|
||||
await ctx.sdk.api.session.rename({ sessionID: value.id, title })
|
||||
await ctx.sdk.api.session.update({ sessionID: value.id, title })
|
||||
} catch (err) {
|
||||
const current = session()
|
||||
const currentCtx = props.serverCtx
|
||||
|
||||
@@ -128,7 +128,7 @@ async function execute(input: RunCommandInput, prepared: Prepared, endpoint: End
|
||||
const model = target.model ? { providerID: target.model.providerID, modelID: target.model.id } : undefined
|
||||
const variant = target.model?.variant
|
||||
if (!target.resume && input.title !== undefined) {
|
||||
await client.session.rename({
|
||||
await client.session.update({
|
||||
sessionID: target.session.id,
|
||||
title: input.title || prepared.message.slice(0, 50) + (prepared.message.length > 50 ? "..." : ""),
|
||||
})
|
||||
|
||||
@@ -233,9 +233,13 @@ export type SessionSwitchModelOperation<E = never> = (
|
||||
input: SessionSwitchModelInput,
|
||||
) => Effect.Effect<SessionSwitchModelOutput, E>
|
||||
|
||||
export type SessionRenameInput = { readonly sessionID: Session.ID; readonly title: string }
|
||||
export type SessionRenameOutput = void
|
||||
export type SessionRenameOperation<E = never> = (input: SessionRenameInput) => Effect.Effect<SessionRenameOutput, E>
|
||||
export type SessionUpdateInput = {
|
||||
readonly sessionID: Session.ID
|
||||
readonly title?: string | undefined
|
||||
readonly permissions?: Permission.Ruleset | undefined
|
||||
}
|
||||
export type SessionUpdateOutput = void
|
||||
export type SessionUpdateOperation<E = never> = (input: SessionUpdateInput) => Effect.Effect<SessionUpdateOutput, E>
|
||||
|
||||
export type SessionMoveInput = {
|
||||
readonly sessionID: Session.ID
|
||||
@@ -1386,7 +1390,7 @@ export interface SessionApi<E = never> {
|
||||
readonly fork: SessionForkOperation<E>
|
||||
readonly switchAgent: SessionSwitchAgentOperation<E>
|
||||
readonly switchModel: SessionSwitchModelOperation<E>
|
||||
readonly rename: SessionRenameOperation<E>
|
||||
readonly update: SessionUpdateOperation<E>
|
||||
readonly move: SessionMoveOperation<E>
|
||||
readonly prompt: SessionPromptOperation<E>
|
||||
readonly command: SessionCommandOperation<E>
|
||||
@@ -1789,12 +1793,6 @@ export type PermissionReplyOperation<E = never> = (
|
||||
input: PermissionReplyInput,
|
||||
) => Effect.Effect<PermissionReplyOutput, E>
|
||||
|
||||
export type PermissionRulesInput = { readonly sessionID: Session.ID; readonly permissions: Permission.Ruleset }
|
||||
export type PermissionRulesOutput = void
|
||||
export type PermissionRulesOperation<E = never> = (
|
||||
input: PermissionRulesInput,
|
||||
) => Effect.Effect<PermissionRulesOutput, E>
|
||||
|
||||
export interface PermissionApi<E = never> {
|
||||
readonly request: { readonly list: PermissionRequestListOperation<E> }
|
||||
readonly saved: { readonly list: PermissionSavedListOperation<E>; readonly remove: PermissionSavedRemoveOperation<E> }
|
||||
@@ -1802,7 +1800,6 @@ export interface PermissionApi<E = never> {
|
||||
readonly list: PermissionListOperation<E>
|
||||
readonly get: PermissionGetOperation<E>
|
||||
readonly reply: PermissionReplyOperation<E>
|
||||
readonly rules: PermissionRulesOperation<E>
|
||||
}
|
||||
|
||||
export type FileListInput = {
|
||||
|
||||
@@ -39,8 +39,8 @@ import type {
|
||||
SessionSwitchAgentOutput,
|
||||
SessionSwitchModelInput,
|
||||
SessionSwitchModelOutput,
|
||||
SessionRenameInput,
|
||||
SessionRenameOutput,
|
||||
SessionUpdateInput,
|
||||
SessionUpdateOutput,
|
||||
SessionMoveInput,
|
||||
SessionMoveOutput,
|
||||
SessionPromptInput,
|
||||
@@ -174,8 +174,6 @@ import type {
|
||||
PermissionGetOutput,
|
||||
PermissionReplyInput,
|
||||
PermissionReplyOutput,
|
||||
PermissionRulesInput,
|
||||
PermissionRulesOutput,
|
||||
FileListInput,
|
||||
FileListOutput,
|
||||
FileFindInput,
|
||||
@@ -446,11 +444,12 @@ const EndpointSessionSwitchModel = (raw: RawClient["server.session"]) => (input:
|
||||
),
|
||||
)
|
||||
|
||||
const EndpointSessionRename = (raw: RawClient["server.session"]) => (input: SessionRenameInput) =>
|
||||
preserveEffect<SessionRenameOutput>()(
|
||||
raw["session.rename"]({ params: { sessionID: input["sessionID"] }, payload: { title: input["title"] } }).pipe(
|
||||
Effect.mapError(mapClientError),
|
||||
),
|
||||
const EndpointSessionUpdate = (raw: RawClient["server.session"]) => (input: SessionUpdateInput) =>
|
||||
preserveEffect<SessionUpdateOutput>()(
|
||||
raw["session.update"]({
|
||||
params: { sessionID: input["sessionID"] },
|
||||
payload: { title: input["title"], permissions: input["permissions"] },
|
||||
}).pipe(Effect.mapError(mapClientError)),
|
||||
)
|
||||
|
||||
const EndpointSessionMove = (raw: RawClient["server.session"]) => (input: SessionMoveInput) =>
|
||||
@@ -745,7 +744,7 @@ const adaptGroupSession = (raw: RawClient["server.session"]) => ({
|
||||
fork: EndpointSessionFork(raw),
|
||||
switchAgent: EndpointSessionSwitchAgent(raw),
|
||||
switchModel: EndpointSessionSwitchModel(raw),
|
||||
rename: EndpointSessionRename(raw),
|
||||
update: EndpointSessionUpdate(raw),
|
||||
move: EndpointSessionMove(raw),
|
||||
prompt: EndpointSessionPrompt(raw),
|
||||
command: EndpointSessionCommand(raw),
|
||||
@@ -1112,14 +1111,6 @@ const EndpointPermissionReply = (raw: RawClient["server.permission"]) => (input:
|
||||
}).pipe(Effect.mapError(mapClientError)),
|
||||
)
|
||||
|
||||
const EndpointPermissionRules = (raw: RawClient["server.permission"]) => (input: PermissionRulesInput) =>
|
||||
preserveEffect<PermissionRulesOutput>()(
|
||||
raw["session.permission.rules"]({
|
||||
params: { sessionID: input["sessionID"] },
|
||||
payload: { permissions: input["permissions"] },
|
||||
}).pipe(Effect.mapError(mapClientError)),
|
||||
)
|
||||
|
||||
const adaptGroupPermission = (raw: RawClient["server.permission"]) => ({
|
||||
request: { list: EndpointPermissionRequestList(raw) },
|
||||
saved: { list: EndpointPermissionSavedList(raw), remove: EndpointPermissionSavedRemove(raw) },
|
||||
@@ -1127,7 +1118,6 @@ const adaptGroupPermission = (raw: RawClient["server.permission"]) => ({
|
||||
list: EndpointPermissionList(raw),
|
||||
get: EndpointPermissionGet(raw),
|
||||
reply: EndpointPermissionReply(raw),
|
||||
rules: EndpointPermissionRules(raw),
|
||||
})
|
||||
|
||||
const EndpointFileList = (raw: RawClient["server.fs"]) => (input?: FileListInput) =>
|
||||
|
||||
@@ -33,8 +33,8 @@ import type {
|
||||
SessionSwitchAgentOutput,
|
||||
SessionSwitchModelInput,
|
||||
SessionSwitchModelOutput,
|
||||
SessionRenameInput,
|
||||
SessionRenameOutput,
|
||||
SessionUpdateInput,
|
||||
SessionUpdateOutput,
|
||||
SessionMoveInput,
|
||||
SessionMoveOutput,
|
||||
SessionPromptInput,
|
||||
@@ -168,8 +168,6 @@ import type {
|
||||
PermissionGetOutput,
|
||||
PermissionReplyInput,
|
||||
PermissionReplyOutput,
|
||||
PermissionRulesInput,
|
||||
PermissionRulesOutput,
|
||||
FileReadInput,
|
||||
FileReadOutput,
|
||||
FileListInput,
|
||||
@@ -640,12 +638,12 @@ export function make(options: ClientOptions) {
|
||||
},
|
||||
requestOptions,
|
||||
),
|
||||
rename: (input: SessionRenameInput, requestOptions?: RequestOptions) =>
|
||||
request<SessionRenameOutput>(
|
||||
update: (input: SessionUpdateInput, requestOptions?: RequestOptions) =>
|
||||
request<SessionUpdateOutput>(
|
||||
{
|
||||
method: "PATCH",
|
||||
path: `/api/session/${encodeURIComponent(input.sessionID)}`,
|
||||
body: { title: input["title"] },
|
||||
body: { title: input["title"], permissions: input["permissions"] },
|
||||
successStatus: 204,
|
||||
declaredStatuses: [400, 401, 404],
|
||||
empty: true,
|
||||
@@ -1519,18 +1517,6 @@ export function make(options: ClientOptions) {
|
||||
},
|
||||
requestOptions,
|
||||
),
|
||||
rules: (input: PermissionRulesInput, requestOptions?: RequestOptions) =>
|
||||
request<PermissionRulesOutput>(
|
||||
{
|
||||
method: "PUT",
|
||||
path: `/api/session/${encodeURIComponent(input.sessionID)}/permission/rules`,
|
||||
body: { permissions: input["permissions"] },
|
||||
successStatus: 204,
|
||||
declaredStatuses: [400, 401, 404],
|
||||
empty: true,
|
||||
},
|
||||
requestOptions,
|
||||
),
|
||||
},
|
||||
file: {
|
||||
read: (input: FileReadInput, requestOptions?: RequestOptions) =>
|
||||
|
||||
@@ -3903,12 +3903,23 @@ export type SessionSwitchModelInput = {
|
||||
|
||||
export type SessionSwitchModelOutput = void
|
||||
|
||||
export type SessionRenameInput = {
|
||||
export type SessionUpdateInput = {
|
||||
readonly sessionID: { readonly sessionID: string }["sessionID"]
|
||||
readonly title: { readonly title: string }["title"]
|
||||
readonly title?: {
|
||||
readonly title?: string | undefined
|
||||
readonly permissions?:
|
||||
| ReadonlyArray<{ readonly action: string; readonly resource: string; readonly effect: "allow" | "deny" | "ask" }>
|
||||
| undefined
|
||||
}["title"]
|
||||
readonly permissions?: {
|
||||
readonly title?: string | undefined
|
||||
readonly permissions?:
|
||||
| ReadonlyArray<{ readonly action: string; readonly resource: string; readonly effect: "allow" | "deny" | "ask" }>
|
||||
| undefined
|
||||
}["permissions"]
|
||||
}
|
||||
|
||||
export type SessionRenameOutput = void
|
||||
export type SessionUpdateOutput = void
|
||||
|
||||
export type SessionMoveInput = {
|
||||
readonly sessionID: { readonly sessionID: string }["sessionID"]
|
||||
@@ -5721,19 +5732,6 @@ export type PermissionReplyInput = {
|
||||
|
||||
export type PermissionReplyOutput = void
|
||||
|
||||
export type PermissionRulesInput = {
|
||||
readonly sessionID: { readonly sessionID: string }["sessionID"]
|
||||
readonly permissions: {
|
||||
readonly permissions: ReadonlyArray<{
|
||||
readonly action: string
|
||||
readonly resource: string
|
||||
readonly effect: "allow" | "deny" | "ask"
|
||||
}>
|
||||
}["permissions"]
|
||||
}
|
||||
|
||||
export type PermissionRulesOutput = void
|
||||
|
||||
export type FileReadInput = {
|
||||
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||
readonly path: string
|
||||
|
||||
@@ -415,7 +415,6 @@ export const make = Effect.fn("PluginHost.make")(function* (
|
||||
: Effect.fail(new Error(`Permission request not found: ${input.requestID}`)),
|
||||
),
|
||||
),
|
||||
rules: sessions.setPermissions,
|
||||
},
|
||||
plugin: {
|
||||
list: () => response(plugin.list()),
|
||||
@@ -532,7 +531,12 @@ export const make = Effect.fn("PluginHost.make")(function* (
|
||||
prompt: sessions.prompt,
|
||||
generate: (input) => sessions.generate(input).pipe(Effect.map((text) => ({ text }))),
|
||||
command: (input) => sessions.command({ ...input, command: input.name }),
|
||||
rename: sessions.rename,
|
||||
update: Effect.fn(function* (input) {
|
||||
yield* sessions.get(input.sessionID)
|
||||
if (input.title !== undefined) yield* sessions.rename({ sessionID: input.sessionID, title: input.title })
|
||||
if (input.permissions !== undefined)
|
||||
yield* sessions.setPermissions({ sessionID: input.sessionID, permissions: input.permissions })
|
||||
}),
|
||||
move: sessions.move,
|
||||
synthetic: sessions.synthetic,
|
||||
interrupt: (input) =>
|
||||
|
||||
@@ -51,7 +51,7 @@ export const Plugin = {
|
||||
const sessionID = input.sessionID ?? context.sessionID
|
||||
const title = input.title.trim()
|
||||
if (!title) return Effect.fail(new ToolFailure({ message: "Session title must not be empty" }))
|
||||
return ctx.session.rename({ sessionID, title }).pipe(
|
||||
return ctx.session.update({ sessionID, title }).pipe(
|
||||
Effect.as({
|
||||
output: { sessionID, title },
|
||||
content: `Renamed session ${sessionID} to ${title}.`,
|
||||
|
||||
@@ -19,6 +19,6 @@ export interface PermissionHooks {
|
||||
readonly evaluate: PermissionEvaluation
|
||||
}
|
||||
|
||||
export type PermissionDomain = Pick<PermissionApi<unknown>, "list" | "get" | "reply" | "rules"> & {
|
||||
export type PermissionDomain = Pick<PermissionApi<unknown>, "list" | "get" | "reply"> & {
|
||||
readonly hook: Hooks<PermissionHooks>
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ export type SessionDomain = Pick<
|
||||
| "command"
|
||||
| "synthetic"
|
||||
| "interrupt"
|
||||
| "rename"
|
||||
| "update"
|
||||
| "move"
|
||||
| "wait"
|
||||
| "context"
|
||||
|
||||
@@ -439,7 +439,6 @@ export function fromPromise(plugin: Plugin) {
|
||||
list: adaptApiMethod(PermissionEndpoints["session.permission.list"], host.permission.list),
|
||||
get: adaptApiMethod(PermissionEndpoints["session.permission.get"], host.permission.get),
|
||||
reply: adaptApiMethod(PermissionEndpoints["session.permission.reply"], host.permission.reply),
|
||||
rules: adaptApiMethod(PermissionEndpoints["session.permission.rules"], host.permission.rules),
|
||||
},
|
||||
plugin: {
|
||||
list: adaptApiMethod(PluginEndpoints["plugin.list"], host.plugin.list),
|
||||
@@ -581,7 +580,7 @@ export function fromPromise(plugin: Plugin) {
|
||||
command: adaptApiMethod(SessionEndpoints["session.command"], host.session.command),
|
||||
synthetic: adaptApiMethod(SessionEndpoints["session.synthetic"], host.session.synthetic),
|
||||
interrupt: adaptApiMethod(SessionEndpoints["session.interrupt"], host.session.interrupt),
|
||||
rename: adaptApiMethod(SessionEndpoints["session.rename"], host.session.rename),
|
||||
update: adaptApiMethod(SessionEndpoints["session.update"], host.session.update),
|
||||
move: adaptApiMethod(SessionEndpoints["session.move"], host.session.move),
|
||||
wait: adaptApiMethod(SessionEndpoints["session.wait"], host.session.wait),
|
||||
context: adaptApiMethod(SessionEndpoints["session.context"], host.session.context),
|
||||
|
||||
@@ -19,6 +19,6 @@ export interface PermissionHooks {
|
||||
readonly evaluate: PermissionEvaluation
|
||||
}
|
||||
|
||||
export type PermissionDomain = Pick<PermissionApi, "list" | "get" | "reply" | "rules"> & {
|
||||
export type PermissionDomain = Pick<PermissionApi, "list" | "get" | "reply"> & {
|
||||
readonly hook: Hooks<PermissionHooks>
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ export type SessionDomain = Pick<
|
||||
| "command"
|
||||
| "synthetic"
|
||||
| "interrupt"
|
||||
| "rename"
|
||||
| "update"
|
||||
| "move"
|
||||
| "wait"
|
||||
| "context"
|
||||
|
||||
@@ -1438,7 +1438,7 @@
|
||||
},
|
||||
"patch": {
|
||||
"tags": ["session"],
|
||||
"operationId": "session.rename",
|
||||
"operationId": "session.update",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
@@ -1493,8 +1493,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Update the session title.",
|
||||
"summary": "Rename session",
|
||||
"description": "Update mutable session properties.",
|
||||
"summary": "Update session",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
@@ -1502,10 +1502,26 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Permission.Ruleset"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["title"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
@@ -8075,85 +8091,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/permission/rules": {
|
||||
"put": {
|
||||
"tags": ["permission"],
|
||||
"operationId": "session.permission.rules",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"pattern": "^ses"
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundErrorEncoded"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundErrorEncoded"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Replace the session-scoped permission rules. Rules are evaluated after the agent's rules, and the last matching rule wins.",
|
||||
"summary": "Replace session permission rules",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"permissions": {
|
||||
"$ref": "#/components/schemas/Permission.Ruleset"
|
||||
}
|
||||
},
|
||||
"required": ["permissions"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/fs/read/*": {
|
||||
"get": {
|
||||
"tags": ["filesystem"],
|
||||
|
||||
@@ -132,21 +132,4 @@ export const makePermissionGroup = <
|
||||
}),
|
||||
),
|
||||
)
|
||||
.add(
|
||||
HttpApiEndpoint.put("session.permission.rules", "/api/session/:sessionID/permission/rules", {
|
||||
params: { sessionID: Session.ID },
|
||||
payload: Schema.Struct({ permissions: Permission.Ruleset }),
|
||||
success: HttpApiSchema.NoContent,
|
||||
error: SessionNotFoundError,
|
||||
})
|
||||
.middleware(sessionLocationMiddleware)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "session.permission.rules",
|
||||
summary: "Replace session permission rules",
|
||||
description:
|
||||
"Replace the session-scoped permission rules. Rules are evaluated after the agent's rules, and the last matching rule wins.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
.annotateMerge(OpenApi.annotations({ title: "permission", description: "Experimental permission routes." }))
|
||||
|
||||
@@ -355,18 +355,21 @@ export const makeSessionGroup = <
|
||||
),
|
||||
)
|
||||
.add(
|
||||
HttpApiEndpoint.patch("session.rename", "/api/session/:sessionID", {
|
||||
HttpApiEndpoint.patch("session.update", "/api/session/:sessionID", {
|
||||
params: { sessionID: Session.ID },
|
||||
payload: Schema.Struct({ title: Schema.String }),
|
||||
payload: Schema.Struct({
|
||||
title: Schema.String.pipe(Schema.optional),
|
||||
permissions: Permission.Ruleset.pipe(Schema.optional),
|
||||
}),
|
||||
success: HttpApiSchema.NoContent,
|
||||
error: SessionNotFoundError,
|
||||
})
|
||||
.middleware(sessionLocationMiddleware)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "session.rename",
|
||||
summary: "Rename session",
|
||||
description: "Update the session title.",
|
||||
identifier: "session.update",
|
||||
summary: "Update session",
|
||||
description: "Update mutable session properties.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -83,7 +83,7 @@ it.live(
|
||||
Effect.gen(function* () {
|
||||
executed.push(generation)
|
||||
yield* ctx.session
|
||||
.rename({ sessionID: tool.sessionID, title: `${key}:${generation}` })
|
||||
.update({ sessionID: tool.sessionID, title: `${key}:${generation}` })
|
||||
.pipe(Effect.orDie)
|
||||
return { output: key, content: key }
|
||||
}),
|
||||
|
||||
@@ -83,15 +83,6 @@ export const PermissionHandler = HttpApiBuilder.group(Api, "server.permission",
|
||||
return HttpApiSchema.NoContent.make()
|
||||
}),
|
||||
)
|
||||
.handle(
|
||||
"session.permission.rules",
|
||||
Effect.fn(function* (ctx) {
|
||||
yield* sessions
|
||||
.setPermissions({ sessionID: ctx.params.sessionID, permissions: ctx.payload.permissions })
|
||||
.pipe(Effect.catchTag("Session.NotFoundError", missingSession))
|
||||
return HttpApiSchema.NoContent.make()
|
||||
}),
|
||||
)
|
||||
.handle(
|
||||
"permission.saved.list",
|
||||
Effect.fn(function* (ctx) {
|
||||
|
||||
@@ -253,16 +253,23 @@ export const SessionHandler = HttpApiBuilder.group(Api, "server.session", (handl
|
||||
}),
|
||||
)
|
||||
.handle(
|
||||
"session.rename",
|
||||
"session.update",
|
||||
Effect.fn(function* (ctx) {
|
||||
if (ctx.payload.title) {
|
||||
yield* session
|
||||
.rename({ sessionID: ctx.params.sessionID, title: ctx.payload.title })
|
||||
.pipe(Effect.catchTag("Session.NotFoundError", missingSession))
|
||||
return HttpApiSchema.NoContent.make()
|
||||
yield* session.get(ctx.params.sessionID).pipe(Effect.catchTag("Session.NotFoundError", missingSession))
|
||||
if (ctx.payload.title !== undefined) {
|
||||
if (ctx.payload.title) {
|
||||
yield* session
|
||||
.rename({ sessionID: ctx.params.sessionID, title: ctx.payload.title })
|
||||
.pipe(Effect.catchTag("Session.NotFoundError", missingSession))
|
||||
} else {
|
||||
const title = yield* SessionTitle.Service
|
||||
yield* title.generate(ctx.params.sessionID)
|
||||
}
|
||||
}
|
||||
const title = yield* SessionTitle.Service
|
||||
yield* title.generate(ctx.params.sessionID)
|
||||
if (ctx.payload.permissions !== undefined)
|
||||
yield* session
|
||||
.setPermissions({ sessionID: ctx.params.sessionID, permissions: ctx.payload.permissions })
|
||||
.pipe(Effect.catchTag("Session.NotFoundError", missingSession))
|
||||
return HttpApiSchema.NoContent.make()
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -18,7 +18,7 @@ export function DialogSessionRename(props: { sessionID: string; currentTitle?: s
|
||||
const title = value.trim()
|
||||
if (!title) return
|
||||
void client.api.session
|
||||
.rename({ sessionID: props.sessionID, title })
|
||||
.update({ sessionID: props.sessionID, title })
|
||||
.then(() => dialog.clear())
|
||||
.catch((error) =>
|
||||
toast.show({
|
||||
|
||||
@@ -37,7 +37,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||
if (generatingTitles[sessionID]) return
|
||||
setGeneratingTitles(sessionID, true)
|
||||
await client.api.session
|
||||
.rename({ sessionID, title: "" })
|
||||
.update({ sessionID, title: "" })
|
||||
.then(() => {
|
||||
// The HTTP response can beat the renamed event. Keep pending until the new title is projected locally.
|
||||
data.session.invalidate(sessionID)
|
||||
|
||||
@@ -821,7 +821,7 @@ export function Session(props: {
|
||||
const title = input.trim()
|
||||
void (
|
||||
title
|
||||
? client.api.session.rename({ sessionID: route.sessionID, title })
|
||||
? client.api.session.update({ sessionID: route.sessionID, title })
|
||||
: data.session.title.generate(route.sessionID)
|
||||
).catch((error) => toast.error(error))
|
||||
},
|
||||
|
||||
+21
-84
@@ -1438,7 +1438,7 @@
|
||||
},
|
||||
"patch": {
|
||||
"tags": ["session"],
|
||||
"operationId": "session.rename",
|
||||
"operationId": "session.update",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
@@ -1493,8 +1493,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Update the session title.",
|
||||
"summary": "Rename session",
|
||||
"description": "Update mutable session properties.",
|
||||
"summary": "Update session",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
@@ -1502,10 +1502,26 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Permission.Ruleset"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["title"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
@@ -8075,85 +8091,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/permission/rules": {
|
||||
"put": {
|
||||
"tags": ["permission"],
|
||||
"operationId": "session.permission.rules",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"pattern": "^ses"
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundErrorEncoded"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundErrorEncoded"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Replace the session-scoped permission rules. Rules are evaluated after the agent's rules, and the last matching rule wins.",
|
||||
"summary": "Replace session permission rules",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"permissions": {
|
||||
"$ref": "#/components/schemas/Permission.Ruleset"
|
||||
}
|
||||
},
|
||||
"required": ["permissions"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/fs/read/*": {
|
||||
"get": {
|
||||
"tags": ["filesystem"],
|
||||
|
||||
@@ -1438,7 +1438,7 @@
|
||||
},
|
||||
"patch": {
|
||||
"tags": ["session"],
|
||||
"operationId": "session.rename",
|
||||
"operationId": "session.update",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
@@ -1493,8 +1493,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Update the session title.",
|
||||
"summary": "Rename session",
|
||||
"description": "Update mutable session properties.",
|
||||
"summary": "Update session",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
@@ -1502,10 +1502,26 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Permission.Ruleset"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["title"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
@@ -8075,85 +8091,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/permission/rules": {
|
||||
"put": {
|
||||
"tags": ["permission"],
|
||||
"operationId": "session.permission.rules",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"pattern": "^ses"
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundErrorEncoded"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundErrorEncoded"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Replace the session-scoped permission rules. Rules are evaluated after the agent's rules, and the last matching rule wins.",
|
||||
"summary": "Replace session permission rules",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"permissions": {
|
||||
"$ref": "#/components/schemas/Permission.Ruleset"
|
||||
}
|
||||
},
|
||||
"required": ["permissions"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/fs/read/*": {
|
||||
"get": {
|
||||
"tags": ["filesystem"],
|
||||
|
||||
Reference in New Issue
Block a user