Feature ai-gateway-v2: Phase 1 — Gateway core 2.0: capability API, projector dispatch, delete provide (hy-oy5h4)#25
Merged
Conversation
…te provider parsers Refactor @hypaware/ai-gateway into a generic HTTP/SSE capture and row-storage owner. All client/protocol semantics move into adapter plugins through the new full exchange projector API. Capability bumped to breaking 2.0.0. New surface: - registerUpstreamPreset(preset) — adapter-owned routing via optional preset.match() (replaces hardcoded detectProvider()). - registerExchangeProjector(projector) — adapter-owned exchange → conversation messages projection. - localEndpoint, getClient, listClients, registerClient unchanged. Removed from the capability surface: registerExchangeContextProjector and registerMessageEnricher. Projector dispatch in message_projector.js: - Matching projectors sorted by descending priority, then registration order. - First successful non-empty projection wins. - Throws / undefined / invalid output: warn and skip. - No projector matches: zero rows, but pass-through telemetry (aigw.exchange log, aigw.exchange_bytes meter) still fires. Fallback identity (post-projection): when an adapter returns normalized messages without message_id, compute hash id, linearize previous_message_id (only if absent), and stamp attributes.gateway.identity_source = "gateway_fallback". previous_message_id supplied as [] is preserved (root marker). Projector-supplied identity is authoritative — never overridden. Deleted from the gateway package: - Anthropic HTTP+SSE parsing (message_projector.js). - OpenAI Chat and Responses + SSE reconstruction. - Codex header / path / turn-metadata parsing. - Generic context-fallback path, provider inference, Claude-specific attributes.client.claude_version. - /_hypaware/session-context endpoint (proxy.js). - ClaudeSessionContext, localContextForRequest, request-body session lookup, recorder cwd/git_branch injection. Schema unchanged: ai_gateway_messages, SCHEMA_VERSION = 4, proxy_messages_v4. No migration, no backfill. Tests: - ai-gateway-session-context.test.js deleted (endpoint removed). - ai-gateway-message-projector.test.js rewritten to cover the new dispatch surface (priority/seq ordering, error/empty skipping, fallback identity stamping, schema strip) plus the schema column contract. Provider-specific assertions moved out of the gateway and will return in phases 2/3 plugin tests. - ai_gateway_passthrough smoke updated to assert: capability registered at 2.0.0, no cache.append, zero rows for the dev_run_id, and pass-through telemetry (aigw.exchange log with rows_written=0, aigw.exchange_bytes meter) still fires. This phase intentionally breaks Claude + Codex capture (their manifests still require ^1.0.0) until phases 2 and 3 land adapter exchange projectors on the same integration branch.
philcunliffe
added a commit
that referenced
this pull request
May 23, 2026
* chore: seed integration/ai-gateway-v2 for feature flow * hy-oy5h4: Gateway core 2.0 — capability API, projector dispatch, delete provider parsers (#25) Refactor @hypaware/ai-gateway into a generic HTTP/SSE capture and row-storage owner. All client/protocol semantics move into adapter plugins through the new full exchange projector API. Capability bumped to breaking 2.0.0. New surface: - registerUpstreamPreset(preset) — adapter-owned routing via optional preset.match() (replaces hardcoded detectProvider()). - registerExchangeProjector(projector) — adapter-owned exchange → conversation messages projection. - localEndpoint, getClient, listClients, registerClient unchanged. Removed from the capability surface: registerExchangeContextProjector and registerMessageEnricher. Projector dispatch in message_projector.js: - Matching projectors sorted by descending priority, then registration order. - First successful non-empty projection wins. - Throws / undefined / invalid output: warn and skip. - No projector matches: zero rows, but pass-through telemetry (aigw.exchange log, aigw.exchange_bytes meter) still fires. Fallback identity (post-projection): when an adapter returns normalized messages without message_id, compute hash id, linearize previous_message_id (only if absent), and stamp attributes.gateway.identity_source = "gateway_fallback". previous_message_id supplied as [] is preserved (root marker). Projector-supplied identity is authoritative — never overridden. Deleted from the gateway package: - Anthropic HTTP+SSE parsing (message_projector.js). - OpenAI Chat and Responses + SSE reconstruction. - Codex header / path / turn-metadata parsing. - Generic context-fallback path, provider inference, Claude-specific attributes.client.claude_version. - /_hypaware/session-context endpoint (proxy.js). - ClaudeSessionContext, localContextForRequest, request-body session lookup, recorder cwd/git_branch injection. Schema unchanged: ai_gateway_messages, SCHEMA_VERSION = 4, proxy_messages_v4. No migration, no backfill. Tests: - ai-gateway-session-context.test.js deleted (endpoint removed). - ai-gateway-message-projector.test.js rewritten to cover the new dispatch surface (priority/seq ordering, error/empty skipping, fallback identity stamping, schema strip) plus the schema column contract. Provider-specific assertions moved out of the gateway and will return in phases 2/3 plugin tests. - ai_gateway_passthrough smoke updated to assert: capability registered at 2.0.0, no cache.append, zero rows for the dev_run_id, and pass-through telemetry (aigw.exchange log with rows_written=0, aigw.exchange_bytes meter) still fires. This phase intentionally breaks Claude + Codex capture (their manifests still require ^1.0.0) until phases 2 and 3 land adapter exchange projectors on the same integration branch. * hy-zd4ga: Phase 3 - Codex plugin exchange projector (#28) Port OpenAI Chat, OpenAI Responses (JSON + SSE), and ChatGPT Codex (SSE + turn metadata) projection into a single `AiGatewayExchangeProjector` owned by `@hypaware/codex`. Bumps the plugin's capability requirement to `hypaware.ai-gateway@^2.0.0` and adds the new projector to the activate() wiring. Projector behavior: - Matches `/v1/chat/completions`, `/v1/responses`, `/v1/models`, `/backend-api/codex/*`, or any request tagged with the `x-codex-turn-metadata` header. - Parses Chat-shaped requests (`messages: []`) and Responses-shaped requests (`input: ...`) into normalized user-role blocks. Tool calls and tool results map onto `tool_use` / `tool_result` blocks. - Reconstructs streamed assistant messages from `response.output_text.delta` events; falls back to body-level `output_text` or `output` arrays. - Projects Codex headers + turn metadata into both first-class columns (`cwd`, `client_version`, `entrypoint`, `user_type`, `permission_mode`, `is_sidechain`, `request_id`, `prompt_id`) and the `attributes.codex.*` namespace (thread/session/turn ids, workspace, git origin + commit, sandbox, originator, window id). - Always stamps `attributes.codex.identity_source = "gateway_fallback"` because the projector never supplies `message_id` today; the gateway computes hashes and linearizes history for symmetry with the @hypaware/claude adapter. - Reserves a Codex SQLite / log-reader hook behind the `HYPAWARE_CODEX_SQLITE_READS=1` env flag; today no readers are shipped (no-op stub), keeping the real reader out of this bead. Smoke + tests: - `gateway_codex_capture` flow activates `@hypaware/codex` and renames its local fake upstreams to `local-openai` / `local-chatgpt` so they don't collide with the plugin's `openai` / `chatgpt` preset names. The local config entries appear first in the merged routing table and outrank the plugin presets at routing time. - New `test/plugins/codex-exchange-projector.test.js` covers match surface, OpenAI Chat tool-call mapping, Responses SSE reconstruction, Codex header/metadata projection, subagent flipping is_sidechain, identity_source stamping symmetry, log-reader gating, and conversation-id fallback determinism. Gateway core remains free of provider parsing (only `chatgpt-account-id` appears as a default-redacted header, which is a security setting rather than parsing logic). \`npm test\` passes (280 tests). \`npm run typecheck\` clean. \`npm run smoke -- gateway_codex_capture\` and \`npm run smoke -- ai_gateway_passthrough\` both green. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * hy-hko73: Claude plugin exchange projector + state-file session-context (#30) Phase 2 of the ai-gateway-v2 feature flow. Ports the Anthropic HTTP+SSE parsing that phase 1 deleted from the gateway into the `@hypaware/claude` adapter as a single `AiGatewayExchangeProjector`, and moves the session-context channel from the (now-removed) HTTP endpoint to a JSONL file under the plugin's state directory. Plugin (`@hypaware/claude`, bumped to 2.0.0): - New `projector.js` registers `AiGatewayExchangeProjector` and `AiGatewayUpstreamPreset` against `hypaware.ai-gateway@^2.0.0`. Match surface: `/v1/messages*` path OR `anthropic-version` / `x-api-key` / `Authorization: Bearer sk-ant-*` header signature. - `anthropic.js` carries the ported Anthropic Messages HTTP body parse, SSE assistant reconstruction (`message_start`, `content_block_*`, `message_delta`, `message_stop`), conversation id / user id / system text / tools / client-version extraction. - `transcripts.js` reads `<HOME>/.claude/projects/<repo>/<session>.jsonl` (or the exact `transcript_path` when the session-context record supplies one) for native DAG identity. Matches by uuid → projected message: `message_id = provider_uuid = uuid`, `previous_message_id = parentUuid ? [parentUuid] : []`. - `session_context.js` reads/writes `<stateDir>/session-context.jsonl`. `pickLatestMatching` prefers `transcript_path` then `session_id`; newest matching line wins. - On a missing transcript the projector returns messages without `message_id`, the gateway computes hash identity + stamps `attributes.gateway.identity_source="gateway_fallback"`, and the projector adds `attributes.claude.identity_source="gateway_fallback"` for Claude-specific debuggability. - `settings.js` swaps the managed hook command from `--port <port>` to `--state-file <abspath>`; the `_hypaware` marker carries both port (still needed for `ANTHROPIC_BASE_URL`) and state_file. - Deleted `enricher.js` (gateway 2.0 removed `registerMessageEnricher`; the projector inlines what enrichment did). CLI: - `hyp claude-hook session-context --state-file <path>` appends one JSONL record per hook event (session_id, cwd, optional transcript_path / git_branch / ts). No daemon required — the file is read at projection time. Caller-side cleanup of stale `^1.0.0` ranges (phase 1 missed these): - `src/core/cli/core_commands.js` and `src/core/cli/walkthrough.js` require `^2.0.0`. - `src/core/config/validate.js` first-party metadata updated for ai-gateway (provides 2.0.0), claude and codex (both require ^2.0.0; codex projector landed in #28 alongside this). - `walkthrough_*_to_first_query` smokes require `^2.0.0`; their remaining contract assertions (zero ai_gateway_messages rows because they POST to /v1/echo, not /v1/messages) are phase-4 work per the shared-harness scope. Tests: - `test/plugins/claude-projector-identity.test.js` covers native uuid identity, root `[]` previous_message_id, missing-log fallback marker, cwd/git_branch propagation from the state file, and the three `match()` paths (header signature, /v1/messages path, none). - `test/plugins/claude-session-context-hook.test.js` is the hook→state-file→projector roundtrip — replaces the deleted `ai-gateway-session-context.test.js`. - `test/core/command-dispatch.test.js` updated for the `--state-file` flag and the fake gateway capability bumped to 2.0.0 surface (with `registerExchangeProjector`). - `hypaware-core/smoke/flows/gateway_claude_capture.js` rewritten to activate both plugins, stage a JSONL transcript fixture, drive the hook, and assert both native-DAG and fallback-identity rows. - `claude_attach_detach` smoke updated for the new marker shape and the `--state-file` hook command line. 277 tests / typecheck / lint clean. Smokes green: - gateway_claude_capture - claude_attach_detach - ai_gateway_passthrough - daemon_foreground_start_stop - core_boot_noop Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * hy-1l4nl: Phase 4 - gateway API tests + ship gate (#31) Adds dedicated gateway-package unit tests for the post-2.0 capability API and proxy routing now that provider-specific projection logic lives in the Claude and Codex plugins: - test/plugins/ai-gateway-api.test.js covers registerExchangeProjector validation (name/match/project required, missing-priority preserved), registration-order _seq assignment, plus registerUpstreamPreset, registerClient/getClient/listClients, and localEndpoint shape. - test/plugins/ai-gateway-proxy-routing.test.js covers compileUpstreams ordering (priority desc, then prefix length, then registration order), base_url validation, matchUpstream first-match-wins + short-circuit + throw-as-non-match + path-prefix fallback + lowercased array-valued header view. - test/plugins/ai-gateway-message-projector.test.js gains three tests covering invalid-shape-skipped, all-projectors-fail returns zero rows with aigw.projector_error/_invalid_output/message_projection_skipped warnings, and skipping a non-matching projector without calling its project(). proxy.js exports matchUpstream and compileUpstreams so the routing tests can exercise them in isolation; the runtime call sites are unchanged. The gateway package no longer asserts Anthropic/OpenAI/Codex protocol details - phase 1 already stripped them and phases 2/3 added the plugin-side coverage in claude-projector-identity, claude-session- context-hook, and codex-exchange-projector. Pass-through telemetry on the all-projectors-fail path is gated end-to-end by the existing ai_gateway_passthrough smoke (no projector -> zero rows + aigw.exchange log emitted). Final check: npm test (319 pass), ai_gateway_passthrough, gateway_codex_capture, and gateway_claude_capture smokes all green. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: address ai gateway v2 review findings --------- Co-authored-by: feature-launch <feature-launch@gas.city> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Feature ai-gateway-v2: Phase 1 — Gateway core 2.0: capability API, projector dispatch, delete provide
Implemented: gateway core 2.0 — new capability surface (registerUpstreamPreset/registerExchangeProjector/registerClient + getClient/listClients/localEndpoint), projector dispatch with priority+registration-order sort, first-non-empty-wins, fallback identity (hash message_id + linear previous_message_id + attributes.gateway.identity_source='gateway_fallback') only for messages omitting identity. Deleted from gateway package: Anthropic/OpenAI/Codex parsing, ClaudeSessionContext + /_hypaware/session-context endpoint, localContextForRequest, registerExchangeContextProjector, registerMessageEnricher, hardcoded detectProvider, attributes.client.claude_version. Schema unchanged. Tests: ai-gateway-session-context.test.js deleted; ai-gateway-message-projector.test.js rewritten for new dispatch surface + schema. ai_gateway_passthrough smoke updated for 2.0.0 + zero-row-without-projector contract. npm test 266/266, smoke green, typecheck/lint clean.
Delivery
This PR is auto-merged into the integration branch once CI is green. Human
review for the full feature happens on the downstream PR
(
integration/ai-gateway-v2 -> master, draft PR #24), which is opened separately when the featureis ready to ship.