Skip to content

feat(cli): support optional extra headers for hub requests#445

Open
Shujakuinkuraudo wants to merge 2 commits intotiann:mainfrom
Shujakuinkuraudo:feat/hub-extra-headers-draft
Open

feat(cli): support optional extra headers for hub requests#445
Shujakuinkuraudo wants to merge 2 commits intotiann:mainfrom
Shujakuinkuraudo:feat/hub-extra-headers-draft

Conversation

@Shujakuinkuraudo
Copy link
Copy Markdown
Contributor

Summary

This PR adds an optional env-based configuration for attaching extra outbound headers when the CLI/runner connects to a self-hosted hub behind an auth proxy.

Scope is intentionally minimal:

  • env var only: HAPI_EXTRA_HEADERS_JSON
  • applies to outbound CLI -> hub traffic only
  • supports both REST requests and Socket.IO connections
  • no hub-side behavior changes
  • no settings.json persistence in this first iteration

Use case

This helps self-hosted deployments that sit behind an auth proxy or access gateway, such as Cloudflare Access, OAuth2 Proxy, IAP, or other reverse proxies that require extra request headers/cookies.

Example:

export HAPI_EXTRA_HEADERS_JSON='{"Cookie":"CF_Authorization=..."}'

or:

export HAPI_EXTRA_HEADERS_JSON='{"CF-Access-Client-Id":"...","CF-Access-Client-Secret":"..."}'

What changed

  • parse HAPI_EXTRA_HEADERS_JSON in CLI configuration
  • merge those headers into CLI -> hub REST requests
  • pass the same headers into Socket.IO transport options
  • add focused tests for parsing and header propagation
  • add minimal docs for the new env var

Notes

  • built-in request headers still win over custom ones (for example Authorization)
  • invalid JSON is ignored with a warning
  • only string header values are kept
  • response parsing was also relaxed slightly for optional session fields to stay compatible with hubs that omit them

Validation

Ran focused CLI tests:

vitest run src/api/hubExtraHeaders.test.ts src/api/api.extraHeaders.test.ts --config vitest.config.ts

@tiann tiann force-pushed the feat/hub-extra-headers-draft branch from 2ec4461 to f656817 Compare April 12, 2026 01:39
@tiann tiann marked this pull request as ready for review April 12, 2026 12:17
@tiann tiann linked an issue Apr 12, 2026 that may be closed by this pull request
Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • [Major] Relaxing model, modelReasoningEffort, and effort to optional changes the shared Session contract from string | null to string | null | undefined. Downstream code still treats these fields as string | null only, for example toSessionSummary() forwards them into SessionSummary fields that do not allow undefined. That turns a tolerant parser change into a repo-wide type/API-shape change. Evidence shared/src/schemas.ts:178, cli/src/api/types.ts:103; related context shared/src/sessionSummary.ts:18, shared/src/sessionSummary.ts:19, shared/src/sessionSummary.ts:51, shared/src/sessionSummary.ts:52.
    Suggested fix:
    model: z.string().nullable().optional().default(null),
    modelReasoningEffort: z.string().nullable().optional().default(null),
    effort: z.string().nullable().optional().default(null),
    Mirror the same normalization in cli/src/api/types.ts so missing fields stay backward-compatible as null.

Summary
Review mode: initial
1 major issue found: the schema relaxation currently leaks undefined into shared session fields that the rest of the repo still models as string | null. No other high-confidence regressions found in the touched header-propagation paths from static review.

Testing

  • Not run (automation): bun is unavailable in this runner, and repo-wide package typecheck could not be executed here because the installed type dependencies are missing.

HAPI Bot

model: z.string().nullable(),
modelReasoningEffort: z.string().nullable(),
effort: z.string().nullable(),
model: z.string().nullable().optional(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MAJOR] This widens Session.model / modelReasoningEffort / effort to include undefined, but downstream code still declares string | null only. For example, shared/src/sessionSummary.ts returns model: session.model and effort: session.effort into fields that do not accept undefined, so this parser tweak becomes a repo-wide type/API contract change.

Suggested fix:

model: z.string().nullable().optional().default(null),
modelReasoningEffort: z.string().nullable().optional().default(null),
effort: z.string().nullable().optional().default(null),

Mirror the same normalization in cli/src/api/types.ts.

Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • No new high-confidence issues found in the added/modified lines.

Summary

  • Review mode: follow-up after new commits
  • Previous schema-contract finding appears fixed by normalizing missing model / modelReasoningEffort / effort to null in both shared and CLI response schemas.
  • Residual risk: static review only. The added tests cover parsing plus POST/session-socket wiring, but not the /cli/sessions/:id/messages backfill GET path or the machine-scoped socket client.

Testing

  • Not run (automation): bun is unavailable in this runner.

HAPI Bot

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

功能建议:支持为连接 Hub 的请求配置自定义 Header

1 participant