Skip to content

[codebuddy] 2.57.0 scaffold guard misses bare tool names (DSML_INVOKE_PREFIX requires the functions. prefix) - #4596 still reproduces #4852

Closed

Description

@xiaoshuai7038

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.json

payload.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 /healthz when these requests were sent.
  • DSML_CALLS_LINE itself matches fine in all cases - the block opener is identical. Only DSML_INVOKE_PREFIX is too narrow.

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. added
    bugSomething isn't working
    providerProvider adapters, OpenAI-compat presets, upstream API quirks
    on Sep 17, 2026
  2. lidge-jun commented on Sep 17, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 74 / 80

    이 이슈는 CodeBuddy 쪽 “벤더 스캐폴드가 어시스턴트 텍스트로 새는” 버그가 2.57.0에 실렸던 가드(#4776) 이후에도 그대로 재현된다는 보고입니다. 원본은 #4596이었고, 그때 고친 코드는 src/adapters/codebuddy/scaffold-guard.ts입니다. 지금 dev HEAD는 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 문법 자체를 거절하는 쪽이 재발을 줄입니다. 테스트는 리포터가 준 bare Bash 블록과 기존 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 핫픽스가 필요한지 메인테이너가 정해야 한다.

    메인테이너의 판단이 필요한 지점

    • bare 도구 이름 DSML을 전부 거절할지, 아니면 허용 도구 이름 목록을 둘지(목록은 금방 낡음)
    • 2.57.x 패치 릴리스로 올릴지, 2.58.0 트레인에만 넣을지
    • 거절 시 기존처럼 vendor_scaffold_detected로 하드 페일할지, 텍스트만 가리고 턴은 살릴지(현재 설계는 하드 페일)

    너의 추천
    재현·표·원인 줄이 모두 분명한 회귀다. scaffold-guard.ts에서 invoke 감지를 functions. 접두에 묶지 말고 DSML invoke 문법 자체로 넓힌 뒤, bare Bash 블록 회귀 테스트를 넣고 dev에 랜딩하는 쪽을 추천한다. 우선순위는 프로바이더 어댑터 버그 중에서도 높다. 사용자가 보는 증상은 “도구를 안 쓰고 이상한 마크업만 답한다”라서 체감이 크다.

    이 댓글은 grok-bot이 작성했습니다

  3. lidge-jun commented on Sep 17, 2026

    @lidge-jun
    Owner

    Fixed on dev by #4887 (ccf3b03961), released in 2.58.0.

    DSML_INVOKE_PREFIX now stops at the opening quote and requires a name character, so bare Bash, exec, shell, and apply_patch are refused. The parent issue #4596 was already closed; this closes the remaining bare-name gap.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingproviderProvider adapters, OpenAI-compat presets, upstream API quirks

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions