From 37bfcc371945a412fe2b0e1e37ffad396cda6630 Mon Sep 17 00:00:00 2001 From: decolua Date: Wed, 17 Jun 2026 10:11:39 +0700 Subject: [PATCH] open-sse agents.md --- open-sse/AGENTS.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 open-sse/AGENTS.md diff --git a/open-sse/AGENTS.md b/open-sse/AGENTS.md new file mode 100644 index 00000000..a4da782f --- /dev/null +++ b/open-sse/AGENTS.md @@ -0,0 +1,35 @@ +# open-sse + +Provider-agnostic SSE engine: one OpenAI-style request → any provider (LLM chat, image, embedding, tts, stt, search), streamed back in the client's format. + +## Request lifecycle (chat) + +`handlers/chatCore.js` → `services/model.js` `parseModel` (resolve `provider/model`) → `executors/index.js` `getExecutor(provider)` → `translator/index.js` `translateRequest` (client format → provider format) → `executor.execute()` (streams upstream) → `translateResponse` (provider chunks → client format) → SSE out. + +## Directory map + +- `config/` — ALL constants/config (no hardcode elsewhere). `providers.js`/`registry/` (provider defs), `providerModels.js` (alias→models matrix), `runtimeConfig.js` (timeouts, token limits), `*Constants.js`. +- `translator/` — format conversion. `request/-to-.js`, `response/-to-.js`, `schema/` (enums: ROLE, CLAUDE_BLOCK…), `concerns/` (shared logic), `formats/` (per-format). See `tests/translator/AGENTS.md`. +- `executors/` — per-provider upstream call. `base.js` (BaseExecutor), one file per special provider, `index.js` map. +- `providers/` — registry build + `capabilities.js` + `pricing.js`. Entry: `index.js` (PROVIDERS). +- `handlers/` — per-modality cores (chat/image/embedding/tts/stt/search) + sub-provider folders. +- `services/` — `tokenRefresh/`, `usage/`, `combo.js`, `accountFallback.js`, `model.js`. +- `utils/` — streamHandler, error, sessionManager, claudeCloaking. + +## Conventions + +- Config-driven, DRY, camelCase. NEVER hardcode values, models, or block/role strings — use `config/` + `schema/` constants. +- Translator pipeline pivots through OpenAI as the intermediate format. A translator registered on the exact `source:target` pair (e.g. `claude:kiro`) runs as a **direct route**, skipping the lossy double-hop. +- Translators self-register via `register(from, to, reqFn, resFn)` as an import side-effect — new files MUST be imported in `translator/index.js`. + +## How to add + +- **Provider**: copy `providers/REGISTRY_TEMPLATE.js` → `providers/registry/{id}.js`; add models to `config/providerModels.js`. Generic providers need no executor (DefaultExecutor handles OpenAI-compatible APIs). +- **Executor** (only for non-standard upstream): subclass `BaseExecutor` (override `getBaseUrls`/`buildHeaders`/`buildUrl`/`execute`), register in `executors/index.js` map. `getExecutor` falls back to `DefaultExecutor` when absent. +- **Translator**: add `request|response/-to-.js` calling `register(...)`, then import it in `translator/index.js`. Reuse `schema/` + `concerns/` — don't re-implement parsing. + +## Pitfalls + +- OpenAI bridge is lossy (thinking, non-base64 images, tool ids, is_error) — prefer a direct route for fragile pairs. +- `registry/index.js` is an auto-generated static import list; regenerate it (don't hand-edit) after adding a `registry/{id}.js`. REGISTRY_TEMPLATE is excluded by design. +- Special binary/protobuf formats (kiro EventStream, cursor protobuf, commandcode NDJSON) don't round-trip through OpenAI — handle in their executor.