Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/prompt-compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ OpenAI 的文件上传现在不再是“只传文件本体”的通用路径,

兼容层现在只保留 `current_input_file` 这一种拆分方式;旧的 `history_split` 配置字段已移除,读取旧配置时会忽略它且不会再写回。

- `current_input_file` 默认开启;它在统一 completion runtime 入口全局生效,并采用 inline-first 策略。runtime 会先按拆分前的完整 `PromptTokenText` 估算整体上下文 token;当整体上下文不超过 `current_input_file.inline_max_tokens`(默认 `30000`)时,请求保持完整 inline prompt,不上传生成的上下文或工具文件。只有最新 user turn 的纯文本长度达到 `current_input_file.min_chars`(默认 `0`)且整体上下文超过 inline 阈值时,runtime 才会把“完整上下文”合并进 `DS2API_HISTORY.txt` 上下文文件。文件内容会先经过各协议入口的标准化,再序列化成按轮次编号的 `DS2API_HISTORY.txt` 风格 transcript,带有 `# DS2API_HISTORY.txt` 标题和 `=== N. ROLE ===` 分段;如果当前请求带有可用 tools 且 tool choice 不是 `none`,runtime 还会上传 `DS2API_TOOLS.txt`,只承载本次请求的工具名称、描述和参数 schema。live prompt 中则会给出一个 continuation 语气的 user 消息,引导模型从 `DS2API_HISTORY.txt` 的最新状态继续推进,并直接回答最新请求;如果有 `DS2API_TOOLS.txt`,live prompt 会额外要求模型把该文件视为可调用工具和 schema 的权威来源,避免把任务拉回起点,也避免把大段 schema 再次内联到 prompt。
- `current_input_file` 默认开启;它在统一 completion runtime 入口全局生效,并采用 inline-first 策略。runtime 会先按拆分前的完整 `PromptTokenText` 估算整体上下文 token;当整体上下文不超过 `current_input_file.inline_max_tokens`(默认 `30000`)时,请求保持完整 inline prompt,不上传生成的上下文或工具文件。只有最新 user turn 的纯文本长度达到 `current_input_file.min_chars`(默认 `0`)且整体上下文超过 inline 阈值时,runtime 才会把“完整上下文”合并进 `DS2API_HISTORY.txt` 上下文文件。文件内容会先经过各协议入口的标准化,再序列化成按轮次编号的 `DS2API_HISTORY.txt` 风格 transcript,带有 `# DS2API_HISTORY.txt` 标题和 `=== N. ROLE ===` 分段;如果当前请求带有可用 tools 且 tool choice 不是 `none`,runtime 还会上传 `DS2API_TOOLS.txt`,只承载本次请求的工具名称、描述和参数 schema。live prompt 中则会给出一个中性的 continuation user 消息,要求模型使用附加 conversation context 作为当前工作状态并直接回答最新请求;如果有工具文件,live prompt 会额外说明附加 tool reference 是本轮可用工具和 schema 的权威来源,避免把任务拉回起点,也避免把大段 schema 再次内联到 prompt。
- 如果 `current_input_file.enabled=false`,请求会直接透传,不上传任何拆分上下文文件。
- 对客户端回包里的上下文 token 统计,短上下文 inline 路径直接按完整 prompt 计数;触发 `current_input_file` 后 live prompt 被缩短时,仍会沿用**拆分前的完整 prompt 语义**做计数,而不是按缩短后的占位 prompt 计算;否则会把真实上下文显著算小。
- 如果空输出重试最终需要切换托管账号,runtime 会在新账号下重新上传已生成的 `DS2API_HISTORY.txt` 和可选 `DS2API_TOOLS.txt`,再用新的 generated `file_id` 重建 completion payload;客户端原有文件引用会保留在 generated 文件之后。这样可以避免把旧账号不可见的 generated file_id 带到新账号请求里。
Expand Down Expand Up @@ -389,7 +389,7 @@ Parameters: {"type":"object",...}

```json
{
"prompt": "<|begin▁of▁sentence|><|System|>原 system / developer\n\nAvailable tool descriptions and parameter schemas are attached in DS2API_TOOLS.txt...\n\nTOOL CALL FORMAT: ...<|end▁of▁instructions|><|User|>Continue from the latest state in the attached DS2API_HISTORY.txt context. Treat it as the current working state and answer the latest user request directly. Available tool descriptions and parameter schemas are attached in DS2API_TOOLS.txt; use only those tools and follow the tool-call format rules in this prompt.<|Assistant|>",
"prompt": "<|begin▁of▁sentence|><|System|>原 system / developer\n\nAvailable tool descriptions and parameter schemas are attached in a tool reference...\n\nTOOL CALL FORMAT: ...<|end▁of▁instructions|><|User|>Use the attached conversation context as the current working state. Answer the latest user request directly. The attached tool reference lists the available tools and parameter schemas for this request; use only those tools and follow the tool-call format rules in this prompt.<|Assistant|>",
"ref_file_ids": [
"file-current-input-history",
"file-current-input-tools",
Expand Down
2 changes: 1 addition & 1 deletion internal/completionruntime/nonstream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ func TestStartCompletionAppliesCurrentInputFileGlobally(t *testing.T) {
t.Fatalf("expected uploaded file id in ref_file_ids, got %#v", ds.payloads[0]["ref_file_ids"])
}
prompt, _ := ds.payloads[0]["prompt"].(string)
if !strings.Contains(prompt, "Continue from the latest state in the attached DS2API_HISTORY.txt context.") {
if !strings.Contains(prompt, "Use the attached conversation context as the current working state.") {
t.Fatalf("expected continuation prompt, got %q", prompt)
}
if !start.Request.CurrentInputFileApplied || !strings.Contains(start.Request.PromptTokenText, "# DS2API_HISTORY.txt") {
Expand Down
8 changes: 4 additions & 4 deletions internal/httpapi/claude/current_input_file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func TestClaudeDirectAppliesCurrentInputFile(t *testing.T) {
t.Fatalf("expected uploaded history ref id, got %#v", ds.payload["ref_file_ids"])
}
prompt, _ := ds.payload["prompt"].(string)
if !strings.Contains(prompt, "Continue from the latest state in the attached DS2API_HISTORY.txt context.") {
if !strings.Contains(prompt, "Use the attached conversation context as the current working state.") {
t.Fatalf("expected continuation prompt, got %q", prompt)
}
snapshot, err := historyStore.Snapshot()
Expand All @@ -158,7 +158,7 @@ func TestClaudeDirectAppliesCurrentInputFile(t *testing.T) {
if full.HistoryText != string(ds.uploads[0].Data) {
t.Fatalf("expected uploaded current input file to be persisted in history text")
}
if len(full.Messages) != 1 || !strings.Contains(full.Messages[0].Content, "Continue from the latest state in the attached DS2API_HISTORY.txt context.") {
if len(full.Messages) != 1 || !strings.Contains(full.Messages[0].Content, "Use the attached conversation context as the current working state.") {
t.Fatalf("expected persisted message to match upstream continuation prompt, got %#v", full.Messages)
}
}
Expand Down Expand Up @@ -206,8 +206,8 @@ func TestClaudeCurrentInputFileUploadsToolsSeparately(t *testing.T) {
t.Fatalf("expected history and tools ref ids first, got %#v", ds.payload["ref_file_ids"])
}
prompt, _ := ds.payload["prompt"].(string)
if !strings.Contains(prompt, "DS2API_TOOLS.txt") || !strings.Contains(prompt, "TOOL CALL FORMAT") {
t.Fatalf("expected live prompt to reference tools file and retain format instructions, got %q", prompt)
if !strings.Contains(prompt, "tool reference") || !strings.Contains(prompt, "TOOL CALL FORMAT") {
t.Fatalf("expected live prompt to reference tool reference and retain format instructions, got %q", prompt)
}
if strings.Contains(prompt, "Description: search docs") {
t.Fatalf("live prompt should not inline tool descriptions, got %q", prompt)
Expand Down
8 changes: 4 additions & 4 deletions internal/httpapi/gemini/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func TestGeminiDirectAppliesCurrentInputFile(t *testing.T) {
t.Fatalf("expected uploaded history ref id, got %#v", ds.payloads[0]["ref_file_ids"])
}
prompt, _ := ds.payloads[0]["prompt"].(string)
if !strings.Contains(prompt, "Continue from the latest state in the attached DS2API_HISTORY.txt context.") {
if !strings.Contains(prompt, "Use the attached conversation context as the current working state.") {
t.Fatalf("expected continuation prompt, got %q", prompt)
}
snapshot, err := historyStore.Snapshot()
Expand All @@ -202,7 +202,7 @@ func TestGeminiDirectAppliesCurrentInputFile(t *testing.T) {
if full.HistoryText != string(ds.uploadCalls[0].Data) {
t.Fatalf("expected uploaded current input file to be persisted in history text")
}
if len(full.Messages) != 1 || !strings.Contains(full.Messages[0].Content, "Continue from the latest state in the attached DS2API_HISTORY.txt context.") {
if len(full.Messages) != 1 || !strings.Contains(full.Messages[0].Content, "Use the attached conversation context as the current working state.") {
t.Fatalf("expected persisted message to match upstream continuation prompt, got %#v", full.Messages)
}
}
Expand Down Expand Up @@ -250,8 +250,8 @@ func TestGeminiCurrentInputFileUploadsToolsSeparately(t *testing.T) {
t.Fatalf("expected history and tools ref ids first, got %#v", ds.payloads[0]["ref_file_ids"])
}
prompt, _ := ds.payloads[0]["prompt"].(string)
if !strings.Contains(prompt, "DS2API_TOOLS.txt") || !strings.Contains(prompt, "TOOL CALL FORMAT") {
t.Fatalf("expected live prompt to reference tools file and retain format instructions, got %q", prompt)
if !strings.Contains(prompt, "tool reference") || !strings.Contains(prompt, "TOOL CALL FORMAT") {
t.Fatalf("expected live prompt to reference tool reference and retain format instructions, got %q", prompt)
}
if strings.Contains(prompt, "Description: eval") {
t.Fatalf("live prompt should not inline tool descriptions, got %q", prompt)
Expand Down
2 changes: 1 addition & 1 deletion internal/httpapi/openai/chat/chat_history_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ func TestChatCompletionsCurrentInputFilePersistsNeutralPrompt(t *testing.T) {
if len(full.Messages) != 1 {
t.Fatalf("expected continuation prompt to be the only persisted message, got %#v", full.Messages)
}
if !strings.Contains(full.Messages[0].Content, "Continue from the latest state in the attached DS2API_HISTORY.txt context.") {
if !strings.Contains(full.Messages[0].Content, "Use the attached conversation context as the current working state.") {
t.Fatalf("expected continuation prompt to be persisted, got %#v", full.Messages[0])
}
}
14 changes: 7 additions & 7 deletions internal/httpapi/openai/chat/vercel_prepare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func TestHandleVercelStreamPrepareAppliesCurrentInputFile(t *testing.T) {
t.Fatalf("expected payload object, got %#v", body["payload"])
}
promptText, _ := payload["prompt"].(string)
if !strings.Contains(promptText, "Continue from the latest state in the attached DS2API_HISTORY.txt context.") {
if !strings.Contains(promptText, "Use the attached conversation context as the current working state.") {
t.Fatalf("expected continuation prompt, got %s", promptText)
}
if strings.Contains(promptText, "first user turn") || strings.Contains(promptText, "latest user turn") {
Expand Down Expand Up @@ -218,8 +218,8 @@ func TestHandleVercelStreamPrepareUploadsToolsSeparately(t *testing.T) {
payload, _ := body["payload"].(map[string]any)
payloadPrompt, _ := payload["prompt"].(string)
for label, promptText := range map[string]string{"final_prompt": finalPrompt, "payload.prompt": payloadPrompt} {
if !strings.Contains(promptText, "DS2API_TOOLS.txt") || !strings.Contains(promptText, "TOOL CALL FORMAT") {
t.Fatalf("expected %s to reference tools file and retain tool instructions, got %q", label, promptText)
if !strings.Contains(promptText, "tool reference") || !strings.Contains(promptText, "TOOL CALL FORMAT") {
t.Fatalf("expected %s to reference tool reference and retain tool instructions, got %q", label, promptText)
}
if strings.Contains(promptText, "Description: search docs") {
t.Fatalf("expected %s not to inline tool descriptions, got %q", label, promptText)
Expand Down Expand Up @@ -418,7 +418,7 @@ func TestHandleVercelStreamSwitchReuploadsCurrentInputFile(t *testing.T) {
RequestedModel: "deepseek-v4-flash",
ResolvedModel: "deepseek-v4-flash",
ResponseModel: "deepseek-v4-flash",
FinalPrompt: "Continue from the latest state in the attached DS2API_HISTORY.txt context. Available tool descriptions and parameter schemas are attached in DS2API_TOOLS.txt; use only those tools and follow the tool-call format rules in this prompt.",
FinalPrompt: "Use the attached conversation context as the current working state. The attached tool reference lists the available tools and parameter schemas for this request; use only those tools and follow the tool-call format rules in this prompt.",
PromptTokenText: "# DS2API_HISTORY.txt\n\n=== 1. USER ===\nhello\n\n# DS2API_TOOLS.txt\nAvailable tool descriptions and parameter schemas for this request.\n\nYou have access to these tools:\n\nTool: search\nDescription: search docs\nParameters: {\"type\":\"object\"}\n",
HistoryText: "# DS2API_HISTORY.txt\n\n=== 1. USER ===\nhello\n",
CurrentInputFileApplied: true,
Expand Down Expand Up @@ -469,8 +469,8 @@ func TestHandleVercelStreamSwitchReuploadsCurrentInputFile(t *testing.T) {
t.Fatalf("expected reuploaded current input refs plus client ref, got %#v", payload["ref_file_ids"])
}
promptText, _ := payload["prompt"].(string)
if !strings.Contains(promptText, "DS2API_TOOLS.txt") {
t.Fatalf("expected switched payload prompt to retain tools file reference, got %q", promptText)
if !strings.Contains(promptText, "tool reference") {
t.Fatalf("expected switched payload prompt to retain tool reference, got %q", promptText)
}
ok, _, releasedSessionID, pendingCleanups := h.releaseStreamLease(leaseID)
if !ok {
Expand Down Expand Up @@ -520,7 +520,7 @@ func TestHandleVercelStreamSwitchReleaseCleansOldSessionAfterReuploadFailure(t *
RequestedModel: "deepseek-v4-flash",
ResolvedModel: "deepseek-v4-flash",
ResponseModel: "deepseek-v4-flash",
FinalPrompt: "Continue from the latest state in the attached DS2API_HISTORY.txt context.",
FinalPrompt: "Use the attached conversation context as the current working state.",
HistoryText: "# DS2API_HISTORY.txt\n\n=== 1. USER ===\nhello\n",
CurrentInputFileApplied: true,
CurrentInputFileID: "file-old",
Expand Down
4 changes: 2 additions & 2 deletions internal/httpapi/openai/history/current_input_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ func TestApplyCurrentInputFileGoldenTranscriptStability(t *testing.T) {
if !strings.HasPrefix(out.PromptTokenText, wantHistory+"\n"+wantTools+"\n") {
t.Fatalf("prompt token text should start with history, tools, prompt in order, got %q", out.PromptTokenText)
}
if !strings.Contains(out.FinalPrompt, "DS2API_TOOLS.txt") || !strings.Contains(out.FinalPrompt, "TOOL CALL FORMAT") {
t.Fatalf("final prompt should reference tools file and retain format instructions, got %q", out.FinalPrompt)
if !strings.Contains(out.FinalPrompt, "tool reference") || !strings.Contains(out.FinalPrompt, "TOOL CALL FORMAT") {
t.Fatalf("final prompt should reference tool reference and retain format instructions, got %q", out.FinalPrompt)
}
if strings.Contains(out.FinalPrompt, "Description: Search docs") {
t.Fatalf("final prompt should not inline tool descriptions, got %q", out.FinalPrompt)
Expand Down
4 changes: 2 additions & 2 deletions internal/httpapi/openai/history/current_input_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,9 @@ func latestUserInputForFile(messages []any) (int, string) {
}

func currentInputFilePrompt(hasToolsFile bool) string {
prompt := "Continue from the latest state in the attached DS2API_HISTORY.txt context. Treat it as the current working state and answer the latest user request directly."
prompt := "Use the attached conversation context as the current working state. Answer the latest user request directly."
if hasToolsFile {
prompt += " Available tool descriptions and parameter schemas are attached in DS2API_TOOLS.txt; use only those tools and follow the tool-call format rules in this prompt."
prompt += " The attached tool reference lists the available tools and parameter schemas for this request; use only those tools and follow the tool-call format rules in this prompt."
}
return prompt
}
Expand Down
Loading
Loading