Repository navigation
[codebuddy] 2.57.0 scaffold guard misses bare tool names (DSML_INVOKE_PREFIX requires the functions. prefix) - #4596 still reproduces #4852
Description
Client or integration
Codex App
Area
Provider adapter
Summary
Follow-up to #4596. The CodeBuddy scaffold guard that shipped in 2.57.0 (via #4776 / 2e590fe419b) does not match the shape the routed model actually emits, so the leak reported in #4596 still reproduces on the released build.
src/adapters/codebuddy/scaffold-guard.ts (2.57.0, lines 10-11) recognises exactly two markers:
const DSML_CALLS_LINE = "<||DSML|| calls>";
const DSML_INVOKE_PREFIX = "<||DSML|| invoke name="functions.";Refusal requires the invoke line to be followed by name="functions. - a tool name carrying the functions. namespace prefix. The model on this route does not emit that prefix. It writes the bare tool name, so every marker misses and the whole block is forwarded as assistant text.
Reproduction
With 2.57.0 running locally, post an ordinary agent-style turn to the proxy and read the returned text:
curl -s -X POST http://127.0.0.1:10100/v1/responses \
-H 'Content-Type: application/json' \
--data-binary @payload.jsonpayload.json:
{
"model": "codebuddy-cn/deepseek-v4.1-flash",
"stream": false,
"instructions": "You are an autonomous coding agent working in a local git repository. You have an `exec` tool for running shell commands. When the user asks you to inspect the repository, call the exec tool; do not just describe what you would run.",
"input": [
{
"role": "user",
"content": "Run `git status --short --branch` in the current directory using your exec tool, then report the branch name. Do not explain, just call the tool."
}
]
}Reproduced twice out of two attempts, ~6 seconds each, HTTP 200. No error field, no vendor_scaffold_detected code - the guard never fired.
Version
2.57.0
Operating system
macOS 26.5.1 (Darwin 25.5.0, arm64), Node v26.5.0
Provider and model
codebuddy (provider id codebuddy-cn) / deepseek-v4.1-flash
Logs or error output
Raw routed response - this is the entire assistant output, verbatim:
<||DSML|| calls>
<||DSML|| invoke name="Bash">
<||DSML|| parameter name="command" string="true">git status --short --branch</||DSML|| parameter>
</||DSML|| invoke>
</||DSML|| calls>
The tool name the model chose is Bash, which is the only reason the guard missed. The same request produced functions.exec in the original #4596 samples, which is why the marker was written with that prefix.
Screenshots and supporting files
I drove the shipped CodeBuddyScaffoldFilter class directly (2.57.0, no local modification) with one syntactically identical block per tool name. Only the functions.-prefixed names are refused:
| invoke name | guard result |
|---|---|
functions.exec |
refused |
functions.Bash |
refused |
functions.apply_patch |
refused |
Bash |
leaked |
exec |
leaked |
shell |
leaked |
apply_patch |
leaked |
Also replayed through the same filter class: the two samples attached to #4596 (functions.exec, one of them split across deltas) are refused, and the block from this report (Bash) is not. The existing marker logic and the delta-boundary handling both work; the namespace prefix on the invoke target is the only gap.
- Environment note: the package was freshly installed from npm as 2.57.0 with no local modification applied, and the proxy reported 2.57.0 on
/healthzwhen these requests were sent. DSML_CALLS_LINEitself matches fine in all cases - the block opener is identical. OnlyDSML_INVOKE_PREFIXis too narrow.
Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
lidge-jun commentedon Sep 17, 2026
리뷰 · 우선순위 74 / 80
이 이슈는 CodeBuddy 쪽 “벤더 스캐폴드가 어시스턴트 텍스트로 새는” 버그가 2.57.0에 실렸던 가드(#4776) 이후에도 그대로 재현된다는 보고입니다. 원본은 #4596이었고, 그때 고친 코드는
src/adapters/codebuddy/scaffold-guard.ts입니다. 지금devHEAD는7ef3f6745(패키지 2.58.0)이고, 그 파일의 감지 규칙은 아직 그대로입니다.DSML_CALLS_LINE으로 호출 블록 시작을 찾고, 바로 다음 줄이DSML_INVOKE_PREFIX(= invoke name=에functions.접두가 붙은 형태)로 시작해야만 거부로 처리합니다. 주석에도 “calls 줄만으로는 해롭지 않고, functions.* invoke가 따라와야 스캐폴드다”라고 적어 두었습니다.문제는 라우트된 모델이 항상
functions.를 붙이지 않는다는 점입니다. 리포터는 2.57.0 패키지를 그대로 돌리며codebuddy-cn/deepseek-v4.1-flash로 재현했고, 응답 전체가 DSML 블록인데 invoke 이름이 그냥Bash였습니다. 그래서vendor_scaffold_detected도 안 나오고 HTTP 200으로 텍스트가 통과했습니다. 같은 필터 클래스로 표까지 돌려 보면functions.exec/functions.Bash는 거절되고,Bash/exec/shell/apply_patch는 전부 새어 나갑니다. 즉 델타 경계 처리나 calls 줄 매칭은 이미 잘 되고, invoke 대상 이름에 네임스페이스를 강제하는 한 줄만 구멍이 난 상태입니다. #4596 샘플이 마침functions.exec였던 탓에 그 접두가 “안전장치”처럼 보였지만, 실제 모델 출력은 더 넓습니다.지금
dev방향과도 맞습니다. #4846은 계약을 소스 형태가 아니라 행동으로 고정하자는 쪽이고, 이 가드도 “벤더 스캐폴드는 클라이언트로 나가지 않는다”는 행동을 지켜야 합니다. 고치는 자리는 좁습니다.DSML_INVOKE_PREFIX를functions.까지 묶지 말고, invoke 줄 자체(… invoke name=")까지만 본 뒤 이름이 비어 있지 않으면 거절하거나, bare 도구 이름 화이트/블랙을 따로 두지 말고 DSML 문법 자체를 거절하는 쪽이 재발을 줄입니다. 테스트는 리포터가 준 bareBash블록과 기존functions.*블록을 같이 넣으면 됩니다. types.ts/config.ts 대형 분리와는 무관하고, 프로바이더 어댑터 한 파일·가드 계약 테스트 수준이라 리베이스 부담도 작습니다.src/adapters/codebuddy/scaffold-guard.ts라인 10-11 -DSML_INVOKE_PREFIX가functions.까지 포함해서, bare 도구 이름(Bash,exec등) invoke는 스캐폴드로 안 잡힌다.src/adapters/codebuddy/scaffold-guard.ts라인 8-9·41-42 주석 - “functions.*만 스캐폴드”라는 가정이 #4596 당시 샘플에 묶여 있고, 지금 재현 로그와 어긋난다.src/adapters/codebuddy/scaffold-guard.ts라인 80-84 - invoke 줄이 접두와 안 맞으면 그냥 통과한다. bare 이름일 때 fail로 가지 않는 분기 자체가 구멍이다.경로 테스트 스위트 - bare DSML +
functions.*DSML을 같이 고정하는 회귀가 없으면 #4596이 또 “한쪽 샘플만 고친” 채로 풀릴 수 있다.경로 출시 트레인 - 버그는 2.57.0(npm latest)에서 재현되고,
dev는 이미 2.58.0이다. 가드만 고친 뒤 2.57.x 핫픽스가 필요한지 메인테이너가 정해야 한다.메인테이너의 판단이 필요한 지점
vendor_scaffold_detected로 하드 페일할지, 텍스트만 가리고 턴은 살릴지(현재 설계는 하드 페일)너의 추천
재현·표·원인 줄이 모두 분명한 회귀다.
scaffold-guard.ts에서 invoke 감지를functions.접두에 묶지 말고 DSML invoke 문법 자체로 넓힌 뒤, bareBash블록 회귀 테스트를 넣고dev에 랜딩하는 쪽을 추천한다. 우선순위는 프로바이더 어댑터 버그 중에서도 높다. 사용자가 보는 증상은 “도구를 안 쓰고 이상한 마크업만 답한다”라서 체감이 크다.이 댓글은 grok-bot이 작성했습니다
lidge-jun commentedon Sep 17, 2026
Fixed on
devby #4887 (ccf3b03961), released in 2.58.0.DSML_INVOKE_PREFIXnow stops at the opening quote and requires a name character, so bareBash,exec,shell, andapply_patchare refused. The parent issue #4596 was already closed; this closes the remaining bare-name gap.