feat: add agent-type request header to CoStrict provider
在 CoStrict provider 的所有 API 请求中注入 agent-type header,
反映当前会话所使用的 agent 或 skill,默认值为 "build"。
- fetch.ts: createCoStrictFetch 接受可选 agentType 参数,PascalCase
自动转 kebab-case(StrictSpec → strict-spec),注入 agent-type header
- index.ts: queryModelCoStrict 读取 getMainThreadAgentType()(--agent 启动)
或 getActiveSkillName()(slash skill 触发)作为 agentType
- models.ts: /v1/models 请求添加 User-Agent: csc/{VERSION} header
- state.ts: 新增 activeSkillName 状态及 getter/setter
- processSlashCommand.tsx: inline skill 和 fork skill(context:fork)
触发时均调用 setActiveSkillName 记录当前 skill/agent 名
- caches.ts: /clear 时调用 setActiveSkillName(undefined) 重置状态,
避免新会话继承上一会话的 agent-type
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
61b1b595bf
commit
4dcb3a2107
|
|
@ -195,6 +195,8 @@ type State = {
|
|||
sdkBetas: string[] | undefined
|
||||
// Main thread agent type (from --agent flag or settings)
|
||||
mainThreadAgentType: string | undefined
|
||||
// Currently active skill name (set when a /skill-name is invoked)
|
||||
activeSkillName: string | undefined
|
||||
// Remote mode (--remote flag)
|
||||
isRemoteMode: boolean
|
||||
// Direct connect server URL (for display in header)
|
||||
|
|
@ -381,6 +383,8 @@ function getInitialState(): State {
|
|||
sdkBetas: undefined,
|
||||
// Main thread agent type
|
||||
mainThreadAgentType: undefined,
|
||||
// Currently active skill name
|
||||
activeSkillName: undefined,
|
||||
// Remote mode
|
||||
isRemoteMode: false,
|
||||
...(process.env.USER_TYPE === 'ant'
|
||||
|
|
@ -1622,6 +1626,14 @@ export function setMainThreadAgentType(agentType: string | undefined): void {
|
|||
STATE.mainThreadAgentType = agentType
|
||||
}
|
||||
|
||||
export function getActiveSkillName(): string | undefined {
|
||||
return STATE.activeSkillName
|
||||
}
|
||||
|
||||
export function setActiveSkillName(skillName: string | undefined): void {
|
||||
STATE.activeSkillName = skillName
|
||||
}
|
||||
|
||||
export function getIsRemoteMode(): boolean {
|
||||
return STATE.isRemoteMode
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
import { feature } from 'bun:bundle'
|
||||
import {
|
||||
clearInvokedSkills,
|
||||
setActiveSkillName,
|
||||
setLastEmittedDate,
|
||||
} from '../../bootstrap/state.js'
|
||||
import { clearCommandsCache } from '../../commands.js'
|
||||
|
|
@ -115,6 +116,8 @@ export function clearSessionCaches(
|
|||
if (!hasPreserved) clearAllDumpState()
|
||||
// Clear invoked skills cache (each entry holds full skill file content)
|
||||
clearInvokedSkills(preservedAgentIds)
|
||||
// Reset active skill name so new session doesn't inherit previous session's agent-type
|
||||
setActiveSkillName(undefined)
|
||||
// Clear git dir resolution cache
|
||||
clearResolveGitDirCache()
|
||||
// Clear dynamic skills (loaded from skill directories)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,15 @@ type CoStrictFetch = typeof fetch & {
|
|||
preconnect?: (url: string | URL) => void
|
||||
}
|
||||
|
||||
// PascalCase / camelCase → kebab-case: "StrictSpec" → "strict-spec", "TDD" → "tdd"
|
||||
function toKebabCase(s: string | undefined): string | undefined {
|
||||
if (!s) return undefined
|
||||
return s
|
||||
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')
|
||||
.replace(/([a-z\d])([A-Z])/g, '$1-$2')
|
||||
.toLowerCase()
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建自定义 fetch 函数,用于 CoStrict API 请求
|
||||
*
|
||||
|
|
@ -47,7 +56,10 @@ type CoStrictFetch = typeof fetch & {
|
|||
* 3. 注入 Authorization 和 CoStrict 特有 headers
|
||||
* 4. 反应性 401 错误恢复(自动重试一次)
|
||||
*/
|
||||
export function createCoStrictFetch(): CoStrictFetch {
|
||||
export function createCoStrictFetch(options?: {
|
||||
agentType?: string
|
||||
}): CoStrictFetch {
|
||||
const agentType = toKebabCase(options?.agentType) || 'build'
|
||||
const costrictFetch = async (
|
||||
input: RequestInfo | URL,
|
||||
init?: RequestInit,
|
||||
|
|
@ -94,6 +106,7 @@ export function createCoStrictFetch(): CoStrictFetch {
|
|||
headers.set('X-Title', 'CoStrict-CLI')
|
||||
headers.set('X-Costrict-Version', `costrict-cli-${VERSION}`)
|
||||
headers.set('X-Request-ID', randomUUID())
|
||||
headers.set('agent-type', agentType)
|
||||
headers.set('zgsm-client-id', creds.machine_id)
|
||||
headers.set('zgsm-client-ide', 'cli')
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import { resolveCoStrictModel } from './modelMapping.js'
|
|||
import { getCoStrictBaseURL } from './auth.js'
|
||||
import { loadCoStrictCredentials } from './credentials.js'
|
||||
import { isOpenAIThinkingEnabled } from '../../services/api/openai/requestBody.js'
|
||||
import { getMainThreadAgentType, getActiveSkillName } from '../../bootstrap/state.js'
|
||||
|
||||
/**
|
||||
* CoStrict 查询路径
|
||||
|
|
@ -93,7 +94,9 @@ export async function* queryModelCoStrict(
|
|||
const openaiToolChoice = anthropicToolChoiceToOpenAI(options.toolChoice)
|
||||
|
||||
// 6. 创建专用的 CoStrict OpenAI 客户端(不缓存,每次使用新的 fetch)
|
||||
const costrictFetch = createCoStrictFetch()
|
||||
const costrictFetch = createCoStrictFetch({
|
||||
agentType: getMainThreadAgentType() ?? getActiveSkillName(),
|
||||
})
|
||||
const client = new OpenAI({
|
||||
apiKey: 'costrict-managed', // 实际 token 由 createCoStrictFetch 注入
|
||||
baseURL: chatBaseURL,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ export async function fetchCoStrictModels(
|
|||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: 'application/json',
|
||||
'User-Agent': `csc/${MACRO.VERSION}`,
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import type {
|
|||
ProgressMessage,
|
||||
UserMessage,
|
||||
} from 'src/types/message.js'
|
||||
import { addInvokedSkill, getSessionId } from '../../bootstrap/state.js'
|
||||
import { addInvokedSkill, getSessionId, setActiveSkillName } from '../../bootstrap/state.js'
|
||||
import { COMMAND_MESSAGE_TAG, COMMAND_NAME_TAG } from '../../constants/xml.js'
|
||||
import type { CanUseToolFn } from '../../hooks/useCanUseTool.js'
|
||||
import {
|
||||
|
|
@ -162,6 +162,8 @@ async function executeForkedSlashCommand(
|
|||
? { ...baseAgent, effort: command.effort }
|
||||
: baseAgent
|
||||
|
||||
setActiveSkillName(agentDefinition.agentType ?? command.name)
|
||||
|
||||
logForDebugging(
|
||||
`Executing forked slash command /${command.name} with agent ${agentDefinition.agentType}`,
|
||||
)
|
||||
|
|
@ -1230,6 +1232,7 @@ async function getMessagesForPromptSlashCommand(
|
|||
skillContent,
|
||||
getAgentContext()?.agentId ?? null,
|
||||
)
|
||||
setActiveSkillName(command.name)
|
||||
|
||||
const metadata = formatCommandLoadingMetadata(command, args)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user