feat: add secure multi-runtime controls
Make agent backends configurable and governable with encrypted credentials, explicit context sharing, and tool approval boundaries. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
parent
1b6178b841
commit
698a15ad14
+118
-2
@@ -4,13 +4,113 @@ export const agentRequestSchema = z.object({
|
||||
requestId: z.string().uuid(),
|
||||
conversationId: z.string().min(1).max(128),
|
||||
prompt: z.string().trim().min(1).max(100_000),
|
||||
workspace: z.string().max(2_048).optional()
|
||||
contextIds: z.array(z.string().uuid()).max(8).optional()
|
||||
})
|
||||
|
||||
export type AgentRequest = z.infer<typeof agentRequestSchema>
|
||||
|
||||
export const runtimeProviderSchema = z.enum([
|
||||
'auto',
|
||||
'bigtoken',
|
||||
'opencode',
|
||||
'continue'
|
||||
])
|
||||
|
||||
export const toolApprovalPolicySchema = z.enum([
|
||||
'always',
|
||||
'session',
|
||||
'workspace',
|
||||
'policy'
|
||||
])
|
||||
|
||||
export const defaultRuntimeSettings = {
|
||||
provider: 'auto',
|
||||
bigtokenBaseUrl: 'https://bigtoken.ai',
|
||||
bigtokenModel: 'sonnet-5',
|
||||
toolApproval: 'always'
|
||||
} as const
|
||||
|
||||
export const runtimeSettingsInputSchema = z
|
||||
.object({
|
||||
provider: runtimeProviderSchema,
|
||||
bigtokenBaseUrl: z.string().url().max(2_048),
|
||||
bigtokenModel: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.max(128)
|
||||
.regex(/^[\w./:-]+$/, '模型名称包含不支持的字符'),
|
||||
apiKey: z.discriminatedUnion('action', [
|
||||
z.object({ action: z.literal('keep') }).strict(),
|
||||
z
|
||||
.object({
|
||||
action: z.literal('replace'),
|
||||
value: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.max(8_192)
|
||||
.refine(
|
||||
(value) =>
|
||||
[...value].every((character) => {
|
||||
const code = character.charCodeAt(0)
|
||||
return code > 31 && code !== 127
|
||||
}),
|
||||
{
|
||||
message: 'API Key 包含控制字符'
|
||||
}
|
||||
)
|
||||
})
|
||||
.strict(),
|
||||
z.object({ action: z.literal('clear') }).strict()
|
||||
]),
|
||||
toolApproval: toolApprovalPolicySchema
|
||||
}).strict()
|
||||
.superRefine((settings, context) => {
|
||||
const url = new URL(settings.bigtokenBaseUrl)
|
||||
if (url.protocol !== 'https:') {
|
||||
context.addIssue({
|
||||
code: 'custom',
|
||||
path: ['bigtokenBaseUrl'],
|
||||
message: 'Bigtoken 服务必须使用 HTTPS'
|
||||
})
|
||||
}
|
||||
if (
|
||||
url.username ||
|
||||
url.password ||
|
||||
url.search ||
|
||||
url.hash ||
|
||||
(url.pathname !== '/' && url.pathname !== '')
|
||||
) {
|
||||
context.addIssue({
|
||||
code: 'custom',
|
||||
path: ['bigtokenBaseUrl'],
|
||||
message: '服务地址只能包含 HTTPS origin'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
export type RuntimeSettingsInput = z.infer<typeof runtimeSettingsInputSchema>
|
||||
|
||||
export type RuntimeSettings = {
|
||||
provider: RuntimeSettingsInput['provider']
|
||||
bigtokenBaseUrl: string
|
||||
bigtokenModel: string
|
||||
apiKeyConfigured: boolean
|
||||
credentialSource: 'none' | 'encrypted' | 'environment'
|
||||
secureStorageAvailable: boolean
|
||||
toolApproval: RuntimeSettingsInput['toolApproval']
|
||||
}
|
||||
|
||||
export type ContextAttachment = {
|
||||
id: string
|
||||
name: string
|
||||
size: number
|
||||
preview: string
|
||||
}
|
||||
|
||||
export type AgentRuntimeStatus = {
|
||||
id: 'demo' | 'bigtoken' | 'opencode'
|
||||
id: 'demo' | 'bigtoken' | 'opencode' | 'continue'
|
||||
label: string
|
||||
available: boolean
|
||||
detail: string
|
||||
@@ -34,6 +134,13 @@ export type AgentEvent =
|
||||
state: 'pending' | 'running' | 'completed' | 'failed'
|
||||
summary: string
|
||||
}
|
||||
| {
|
||||
requestId: string
|
||||
type: 'approval'
|
||||
approvalId: string
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
| {
|
||||
requestId: string
|
||||
type: 'done'
|
||||
@@ -64,6 +171,15 @@ export type DesktopApi = {
|
||||
getStatus: () => Promise<AgentRuntimeStatus>
|
||||
run: (request: AgentRequest) => Promise<void>
|
||||
cancel: (requestId: string) => Promise<void>
|
||||
respondApproval: (approvalId: string, approved: boolean) => Promise<void>
|
||||
onEvent: (listener: (event: AgentEvent) => void) => () => void
|
||||
}
|
||||
settings: {
|
||||
getRuntime: () => Promise<RuntimeSettings>
|
||||
updateRuntime: (input: RuntimeSettingsInput) => Promise<RuntimeSettings>
|
||||
}
|
||||
context: {
|
||||
selectFiles: () => Promise<ContextAttachment[]>
|
||||
remove: (contextId: string) => Promise<void>
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user