| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- // 每个 Run 一个短期令牌:引擎调用网关时携带,网关据此确定会话、工作区与访问策略;Run 结束即作废。
- // Codex 的会话在 app-server 中保持加载,MCP 连接沿用第一次对话时的请求头(thread/resume 不会更新),
- // 所以 Codex 每个会话使用固定的令牌字符串:每次 Run 开始时重新绑定到当前 Run,结束后失效,下次 Run 再绑定
- import crypto from 'node:crypto'
- import type { AppSettings, KnowledgeRootDto, PermissionMode } from '@agent-server/shared'
- import type { ResolvedAccess } from '../services/access-policy'
- import type { InteractionOutcome, NewApproval } from '../services/interactions'
- export interface GatewayRunContext {
- sessionId: string
- runId: string
- provider: 'claude' | 'codex'
- workspaceDir: string
- access: ResolvedAccess
- permissionMode: PermissionMode
- settings: AppSettings
- knowledgeRoots: KnowledgeRootDto[]
- /** Profile 勾选的第三方 MCP 服务 */
- mcpServerIds: string[]
- audit: (kind: 'gateway_call' | 'network_denied' | 'file_access_denied' | 'approval', summary: string, detail?: unknown) => void
- /** 发起审批(与引擎侧的审批相同:显示交互卡片并等待回复) */
- interact: (req: NewApproval) => Promise<InteractionOutcome>
- }
- const MAX_AGE_MS = 24 * 3600 * 1000
- export class RunTokenRegistry {
- private tokens = new Map<string, { ctx: GatewayRunContext; issuedAt: number }>()
- /** 会话 → 固定令牌(只用于 Codex) */
- private sessionTokens = new Map<string, string>()
- issue(ctx: GatewayRunContext, opts: { stablePerSession?: boolean } = {}): string {
- let token = opts.stablePerSession ? this.sessionTokens.get(ctx.sessionId) : undefined
- if (!token) {
- token = `rt_${crypto.randomBytes(32).toString('base64url')}`
- if (opts.stablePerSession) this.sessionTokens.set(ctx.sessionId, token)
- }
- this.tokens.set(token, { ctx, issuedAt: Date.now() })
- return token
- }
- get(token: string | undefined): GatewayRunContext | null {
- if (!token) return null
- const e = this.tokens.get(token)
- if (!e) return null
- if (Date.now() - e.issuedAt > MAX_AGE_MS) {
- this.tokens.delete(token)
- return null
- }
- return e.ctx
- }
- /** Run 结束:令牌失效(固定令牌的字符串保留,下次 Run 重新绑定) */
- revoke(token: string) {
- this.tokens.delete(token)
- }
- /** 会话删除时调用 */
- forgetSession(sessionId: string) {
- const token = this.sessionTokens.get(sessionId)
- if (token) this.tokens.delete(token)
- this.sessionTokens.delete(sessionId)
- }
- }
|