Community생산성 & 협업github.com

Prism-Shadow/model-message-stream-protocol

MMSP 자체 개발을 위한 고정된 워크플로우 — 모델 지원 추가/업데이트, 페이지 변경. 이 저장소에서 새 모델이나 프로토콜 버전 지원, llmsdk_docs 동기화, 제공자 클라이언트 구현, 플레이그라운드/트레이서/사이트 변경 시 사용합니다. 문서 동기화, 실시간 API 캡처, Python/TypeScript 쌍 구현, 모델 범위 E2E 테스트, 세 페이지에 대한 UI 규칙을 다룹니다.

model-message-stream-protocol란 무엇인가요?

이 스킬은 MMSP (Model Message Stream Protocol) 저장소에서 모델 지원을 추가하거나 업데이트하는 전체 개발 워크플로우를 안내합니다. 사용자가 특정 제공자의 공식 문서를 `llmsdk_docs/` 디렉토리에 동기화하고, 실제 API 호출을 캡처하여 `api_captures/`에 저장하며, 캡처된 데이터를 기반으로 Python과 TypeScript 클라이언트를 쌍으로 구현하도록 돕습니다. 또한, 제공자별 테스트, 체인지로그 업데이트, UI 페이지(플레이그라운드, 트레이서, 사이트) 변경을 위한 규칙을 제공합니다. 이 스킬은 주로 Claude Code, Cursor, Codex와 같은 AI 에이전트가 MMSP 저장소에서 작업할 때 사용되며, 사용자에게 명시적으로 물어보고 확인해야 하는 단계를 표시하여 실수를 방지합니다.

지원 대상✓Claude Code✓Codex CLI~Cursor✓Gemini CLI
npx skills add https://github.com/Prism-Shadow/model-message-stream-protocol/tree/HEAD/.agents/skills/mmsp-dev

Installed? Explore more 생산성 & 협업 skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

MMSP 개발 워크플로우

모델 지원을 추가하거나 업데이트하는 작업은 아래 단계를 순서대로 따릅니다. 단계에 멈추고 물어보기라고 표시된 경우, 사용자에게 질문하고 문제가 해결될 때까지 중단하며, 직접 빈칸을 채우지 마십시오.

디렉토리 맵

llmsdk_docs/<model_version>/      공식 문서 스냅샷, 모델 세대당 하나의 폴더 (README.md + docs/)
api_captures/<protocol>/          Git에서 무시되는 원시 API 캡처: 요청 페이로드 + 스트림 이벤트
src_py/mmsp/<client_type>/        Python 클라이언트, 클라이언트 유형당 하나의 폴더: <vendor>_official/ 또는 <protocol>/
src_py/mmsp/auto_client.py        client_type 이름으로 클라이언트를 생성; 모델 ID의 패밀리가 공식 클라이언트 이름을 결정
src_ts/src/<client_type>/         TypeScript 클라이언트, Python 폴더를 미러링
src_ts/src/autoClient.ts          TypeScript 라우팅, auto_client.py 미러링
src_py/tests/test_client.py       매개변수화된 E2E 테스트 (환경 변수로 게이트된 AVAILABLE_MODELS)
src_ts/tests/client.test.ts       TypeScript용 동일
changelog/unreleased/             출시되지 않은 변경 사항이 저장되는 곳; 릴리스 시 버전 이름으로 변경
changelog/<version>/              릴리스 요약 (README.md) 및 각 항목당 하나의 상세 파일
changelog/README.md               항목 형식: 메타데이터 블록, 본문 규칙, 이중 언어 페어링
CHANGELOG.md                      각 릴리스당 한 줄 요약, changelog/로 링크
src_py/mmsp/integration/          플레이그라운드, 트레이서 페이지 및 MMSP 서버, src_ts/src/integration/에 미러링
site/                             mmsp.penguin.ooo의 Astro 사이트
.agents/skills/mmsp-dev/kill-ai-slop/  아래 UI 작업을 위한 공급된 AI 슬롭 가이드 및 스캐너
<name>.zh.md                      중국어 대응 파일, changelog/의 모든 파일에 필요

1단계 — 공식 문서를 llmsdk_docs/에 동기화

  • 소스는 모델 공급업체의 공식 문서 사이트여야 합니다 (예: docs.anthropic.com, platform.openai.com, ai.google.dev). 타사 미러, 블로그 게시물, 또는 모델 메모리를 절대 사용하지 마십시오.
  • llmsdk_docs/<model_version>/ 아래에 기존 폴더 규칙을 따라 스냅샷을 저장하고, llmsdk_docs/README.md에 폴더를 나열하십시오. 이 워크플로우를 실행하는 것은 llmsdk_docs/ 편집을 금지하는 저장소 규칙에 대한 명시적 요청입니다.
  • 가져온 문서가 기존 스냅샷과 다른 경우, 새 공식 문서가 우선합니다: 이전 파일을 그 자리에서 업데이트하십시오.
  • 스냅샷은 구현하기에 충분히 완전해야 합니다: 요청/응답 스키마, 스트리밍 이벤트 시퀀스, 생각 출력, 도구 호출, 사용량 필드, 오류 응답.
  • 멈추고 물어보기 공식 URL이 불확실하거나 페이지를 가져올 수 없는 경우. 사용자가 수동으로 내용을 붙여넣을 수 있습니다.

2단계 — 실시간 API 교환을 api_captures/에 캡처

  • 게이트: 제공자의 API 키 환경 변수가 설정되고 사용 가능해야 합니다. src_py/tests/test_client.py (AVAILABLE_MODELS 게이팅 및 _create_client)와 동일한 환경 변수 및 기본 URL을 사용하십시오. 멈추고 물어보기 키가 누락된 경우 사용자에게 키를 제공하도록 요청하십시오; 키 없이 워크플로우를 계속해서는 안 됩니다.
  • 제공자의 공식 SDK, 또는 문서에 정확히 설명된 대로 원시 HTTP를 사용하여, 생각 기능이 활성화된 하나의 스트리밍 도구 호출 요청을 실행한 다음, 도구 결과를 다시 보내어 보조 턴이 어떻게 재전송되는지 보여주십시오.
  • 전체 교환을 수정하지 않고 api_captures/<protocol>/ 아래에 저장하십시오 (git-ignored), 예: round1.request.json과 모든 원시 스트림 이벤트를 순서대로 포함하는 round1.stream.jsonl. 자격 증명을 절대 저장하지 마십시오.
  • 교환 중 일부를 JSON으로 직렬화할 수 없는 경우 (바이너리 페이로드, 비-JSON 값을 보유하는 SDK 객체), str() 형태를 저장하고 그로부터 분석하십시오. 컨테이너를 구문 분석 가능하게 유지하십시오: 텍스트를 JSON 객체로 감싸 .jsonl이 한 줄에 하나의 JSON 값으로 유지되도록 하거나 ({"unserializable_str": "<str(event)>"}, 이벤트를 스트림 순서대로 유지), 직렬화할 수 있는 것이 전혀 없을 때 전체 교환을 형제 .txt 파일에 넣으십시오. str() 캡처는 여전히 API가 반환한 것의 권위 있는 기록입니다. 이벤트를 버리거나, 유효한 JSON으로 수동 편집하거나, 직렬화 실패로 인해 문서로 대체하지 마십시오.
  • 멈추고 물어보기 API 오류 (유효하지 않은 키, 할당량 부족, 속도 제한)가 발생한 경우. 응답을 모의하거나 문서만으로 계속하지 마십시오.
  • 캡처는 기본 구현 참조이며 문서보다 우선합니다: 둘이 일치하지 않는 경우, API가 실제로 반환한 것을 구현하십시오.
  • 그런 다음 재생을 프로브하십시오. 캡처는 API가 보내는 것만 보여주지, 되받아야 하는 것은 보여주지 않기 때문입니다. 보조 턴을 반복적으로 재전송하되, 매번 하나의 후보 필드를 제거하십시오 — 추론 항목의 id, 그 내용, 전체 추론 항목, 유지하고 싶었던 각 필드 — 어떤 제거가 모델의 동작을 손상시키지 않고 API에서 여전히 수락되는지 기록하십시오. 그 결과가, 응답의 형태가 아니라, 3단계가 저장할 내용을 결정합니다. 프로브 결과를 캡처 옆에 저장하십시오.

3단계 — Python 및 TypeScript 클라이언트 구현

  • 클라이언트 유형당 하나의 폴더, 그 이름을 따서 명명: 공급업체당 공식 클라이언트 (openai_official/, anthropic_official/, google_official/, zai_official/, moonshot_official/, deepseek_official/, minimax_official/)는 공급업체 자체 API를 사용하며, 공급업체 모델의 모든 세대를 알고, 환경에서 공급업체의 키를 읽습니다; 와이어 프로토콜당 호환 클라이언트 (openai_responses/, openai_chat/, openai_chat_vllm_adapter/, openai_embedding/, ant_messages/, google_genai/, mmsp/)는 모든 엔드포인트에 대해 해당 프로토콜을 사용합니다. 클래스는 폴더 이름을 따서 명명되고 (OpenAIOfficialClient, OpenaiChatClient), 클라이언트 유형은 하이픈이 있는 폴더 이름입니다 (openai-official, openai-chat).
    • 공급업체 모델의 새 세대는 공급업체의 공식 클라이언트에 들어갑니다. 새 프로토콜(캡처 + 문서)을 클라이언트가 오늘 보내는 것과 비교하십시오; 세대가 다른 경우, 단일 키 이름이라도, 명시적 버전 ("4-6" in self._model, "gpt-6" in self._model)으로 클라이언트 내에서 세대를 구분하고, "claude" in model과 같은 베어 하위 문자열로 절대 구분하지 마십시오, 그리고 이전 세대가 계속 작동하도록 유지하십시오. 사용자가 명시적으로 지시하지 않는 한 세대를 절대 삭제하지 마십시오.
    • 새 공급업체는 새 공식 클라이언트 폴더, auto_client.py/autoClient.ts의 새 <vendor>-official 클라이언트 유형, 그리고 거기의 모델 패밀리 테이블에 새 행을 얻습니다: 패밀리는 공급업체 모델의 모든 ID가 시작하는 접두사입니다 (glm-, kimi-), 대소문자를 구분하지 않고 일치.
    • 여러 공급업체가 제공하는 새 와이어 프로토콜은 호환 클라이언트 폴더와 클라이언트 유형을 얻습니다; 호환 클라이언트는 공급업체별 특성을 지니지 않습니다.
  • auto_client.py/autoClient.ts는 client_type이 이름을 지정하는 클라이언트를, 클라이언트 유형의 하나의 테이블에서 생성합니다. client_type 없이, 모델 ID가 시작하는 패밀리가 해당 공식 클라이언트의 이름을 지정합니다; 알려진 패밀리가 없는 ID는 오류를 발생시키고 하나를 요청합니다. 라우팅에는 다른 규칙이 없습니다: 모델 ID에 대한 하위 문자열 일치, 공식 클라이언트 외부의 버전 일치가 없습니다.
  • 자격 증명은 제공된 곳에만 사용됩니다. 이것이 보안 모델이며, 모든 클라이언트 생성자가 따릅니다. api_key로 전달된 키는 그대로 사용됩니다. 환경의 일반 키를 읽는 클라이언트 (openai_official 및 OpenAI 프로토콜 호환 클라이언트의 경우 OPENAI_API_KEY, anthropic_official 및 ant_messages의 경우 ANTHROPIC_API_KEY, google_genai의 경우 GEMINI_API_KEY)는 엔드포인트도 환경에서 올 때만 읽습니다 (OPENAI_BASE_URL/ANTHROPIC_BASE_URL/GEMINI_BASE_URL, 또는 공급업체 자체 기본값): base_url이 주어지고 api_key가 없으면, 해당 키를 다른 엔드포인트로 보내는 대신 생성 시 오류를 발생시킵니다. 이것이 utils의 resolve_credentials/resolveCredentials입니다; 호출하되, 재구현하지 마십시오. 다른 공식 클라이언트 (deepseek_official, zai_official, moonshot_official, minimax_official, google_official)는 주어진 기본 URL에 관계없이 자체 변수 (DEEPSEEK_API_KEY, ZAI_API_KEY, MOONSHOT_API_KEY, MINIMAX_API_KEY, GEMINI_API_KEY)를 읽으며, 일반 키는 절대 읽지 않습니다; 둘 중 하나 없이 오류를 발생시킵니다: <VAR> is required for <Client>. 모든 자격 증명을 공급업체 SDK에 명시적으로 전달하십시오, "없음"을 포함하여 (TypeScript에서 authToken: null, Python에서 지워진 auth_token), SDK는 전달되지 않은 것을 자체 환경 변수에서 채우기 때문입니다. tests/env-credentials.test.ts/tests/test_env_credentials.py의 오프라인 테스트는 제어된 환경에서 모든 클라이언트를 빌드하고 SDK 인스턴스가 보유한 자격 증명을 읽습니다; 새 클라이언트를 추가하십시오.
  • 재생은 최소화해야 하며, 완전할 필요는 없습니다. 재생된 보조 턴은 모델의 동작을 손상시키지 않고 API에서 수락되어야 합니다; 와이어 항목을 필드 대 필드로 복제할 필요는 없습니다. fidelity는 페이로드의 미러가 아니라 예외 채널입니다: 필드는 2단계 프로브에서 요청이 실패하거나 모델이 저하되는 경우에만 그곳에 자리를 얻습니다. 제공자가 생성한 ID(추론 항목 ID, 출력 항목 ID)는 API가 재생성하거나 무시하므로 제외됩니다. API가 요구하는 필드는 포함됩니다: GPT-5.5의 phase, Claude의 생각 signature, 엄격한 업스트림이 요구하는 정확한 추론 필드 이름.
  • 보편적 필드가 이미 전달하는 것을 fidelity에 복사하지 마십시오 — 생각 텍스트, 도구 호출의 이름 또는 구문 분석된 인수. 대신 보편적 필드에서 와이어 항목을 재구축하십시오.
  • tool_call_id는 선택 사항이 아닙니다: 항상 제공자의 호출 ID를 캡처하고 재생하십시오. 와이어 형식이 항목 ID와 호출 ID를 모두 전달하는 경우, 호출 ID가 결과를 해당 호출과 상호 연관시키는 것입니다.
  • 참조 클라이언트를 따르고, 재설계하지 마십시오. openai_official/는 Responses 스타일 프로토콜의 형태이고, openai_chat/는 Chat Completions의 형태입니다: 동일한 메서드 순서, 동일한 제어 흐름, 동일한 이름. 새 클라이언트는 참조 클라이언트에 대한 diff로 읽혀야 합니다, 그렇게 검토될 것이기 때문입니다.
  • 위에서 아래로 읽기 쉽게 유지하십시오. 독자는 점프 없이 파일을 통해 하나의 요청 또는 응답을 곧바로 따라갈 수 있어야 하므로, 인라인이 기본값입니다: SDK의 속성을 직접 읽고 (model_output.delta, model_output.item.call_id), 필드 접근, 사용량 산술, 오류 텍스트를 사용되는 곳에 유지하십시오. 진정으로 크고 자체 포함된 블록(인라인하면 메인 흐름을 묻을 종류, 예: 이미지 가져오기 및 디코딩)에 대해서만 헬퍼를 추출하고, 몇 줄에 대해서는 절대 추출하지 마십시오. 참조 클라이언트의 자체 비공개 메서드 (_convert_thinking_level_*, _convert_tool_choice)를 미러링하고, 그 옆에 계층을 발명하지 마십시오; dict와 SDK 객체를 모두 받는 shim은 절대 그 중 하나가 아닙니다, 이벤트는 SDK 자체 유형으로 타입이 지정되기 때문입니다.
  • 클라이언트는 델타만 생성합니다; 기본 클래스가 항목을 닫습니다. transform_model_output_to_uni_event/transformModelOutputToUniEvent는 하나의 와이어 이벤트를 하나의 UniEvent로 변환하며, 그 content_items는 해당 이벤트가 전달하는 .delta 항목을 와이어 순서대로 포함하고, 절대 .done 항목을 포함하지 않습니다. _streaming_response_internal/_streamingResponseInternal은 요청을 빌드하고, 스트림을 열고, 와이어 이벤트당 하나의 이벤트를 생성합니다: 항목 관리, 누산기, 인수 구문 분석, 사용량 병합, 합성된 중지 없이 단순한 루프입니다. usage_metadata/finish_reason은 와이어가 이를 보고하는 모든 곳에서 stop 이벤트에 탑니다 — Anthropic message_start 및 message_delta, Chat Completions 완료 및 사용량 청크, response.completed — 기본 클래스에 의해 필드별로 병합됩니다; 클라이언트의 stop 이벤트는 공개 스트림을 종료하지 않습니다. 보편적인 것이 없는 와이어 이벤트는 빈 델타 이벤트입니다: 항목 없음, null 사용량 및 완료 이유. 기본 클래스는 모든 델타를 StreamItems (stream_items.py/streamItems.ts)에 전달하며, 이는 도착하는 대로 델타를 내보내고 다음 항목이 시작되거나 클라이언트 스트림이 종료될 때 각 항목을 .done 항목으로 닫습니다; 그런 다음 기본 클래스는 하나의 stop 이벤트를 내보내거나 EmptyResponseError를 발생시킵니다. 프로토콜을 위반하는 이벤트는 모든 모드에서 StreamProtocolError를 발생시키며, 공유 E2E 테스트는 assert_stream_grammar/assertStreamGrammar로 모든 클라이언트의 스트림을 확인합니다.
  • 하나의 항목에 대한 델타는 연속적이며 하나의 fidelity.item_id를 공유합니다. 모델 출력은 직렬이므로, 한 번에 하나의 항목만 스트리밍되며 제공자의 항목 종료 이벤트 (content_block_stop, response.output_item.done, step.stop)는 no-op으로 나열됩니다: 항목을 늦게 또는 순서 없이 닫는 게이트웨이는 아무것도 변경하지 않습니다. 제공자의 자체 ID를 문자열화하여 fidelity.item_id로 전달하십시오: Anthropic 블록 index, Responses 이벤트 item_id 또는 item.id 또는 item.call_id (게이트웨이가 보내지 않을 때 None/undefined), Interactions 단계 index, Chat Completions 와이어 필드 (reasoning_content, reasoning, content, tool_calls), generateContent 부품 종류 (function_call, thought, inline_thinking, inline_data, text); 임베딩 벡터는 없음. StreamItems는 이를 제거하므로, 소비자, 트레이스 또는 기록에 도달하지 않습니다.
  • StreamItems는 항목이 끝나는 위치를 결정합니다; 클라이언트는 절대 그렇게 하지 않습니다. 델타는 다른 item_id를 전달하거나, 다른 종류(하나의 인덱스 아래에서 생각 단계가 텍스트, 이미지, 텍스트로 가는 Interactions는 세 개의 항목)이거나, 스스로 항목을 시작할 때 다음 항목에 속합니다: 이름을 전달하는 tool_call.delta (모든 제공자는 호출의 첫 번째 델타에서 한 번 보내므로, Chat Completions 호출은 자체 ID가 필요 없음), 이미지 (inline_thinking, 또는 image/* MIME 유형의 inline_data, 오디오는 하나의 항목 청크로 스트리밍), 임베딩 벡터. 그렇지 않으면 지금 스트리밍 중인 항목을 계속합니다: ID 없이 델타가 그렇게 하며, 게이트웨이가 ID를 넣는 것과 관계없이 호출의 인수도 마찬가지입니다. 항목의 ID 아래에 단독으로 전송된 Fidelity는 항목의 것입니다, 그것을 전달하는 종류에 관계없이 (이미지 생각 후 Interactions thought_signature). 해당 파일의 종류별 테이블 — 증가하는 필드, 첫 번째 델타의 헤더 필드, 청크가 결합되는 방식 —는 스트림에서 유일한 종류별 코드입니다: done 항목은 증가하는 필드가 모든 추가 델타의 조인으로 대체된 항목의 첫 번째 델타입니다

...

[번역을 위해 잘림]

관련 스킬