Documentation
¶
Overview ¶
Package profiletest implements a CLI-driven end-to-end probe of a ccwrap profile: POST /v1/messages with max_tokens=1 against the configured upstream, then classify the response. The probe is direct in-process — it does not depend on a running ccwrap session and does not appear in the inspect web /recent timeline.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MarshalResult ¶
func MarshalResult(r ProbeResult) ([]byte, error)
MarshalResult formats a ProbeResult as the wire JSON used by both the CLI (`ccwrap profile test --format json`) and the inspect-web `/profile/test` endpoint. *T pointer fields encode as `null` when the underlying value is the zero-value.
Schema:
profile, status, latency_ms, http_status, base_url_host, model_sent, model_sent_rewritten_to, model_echoed, error, skipped_reason
Types ¶
type EgressProbeOptions ¶
type EgressProbeOptions struct {
// Timeout caps the entire probe (DNS+TLS+request+response).
Timeout time.Duration
// Target overrides both env var and hardcoded default. Used by
// tests and by the CLI --target flag. Leave empty in normal paths.
Target string
// NoProxy overlays bypass rules onto the resolved transport. The
// supervisor probe path passes posture.egress.NoProxy here so a
// mode=inherit profile probes through the same bypass list the
// forward path honors — egress.Resolve's default branch drops
// NoProxy (only resolveFromEnv populates it), so without this
// overlay a probe through a flag-shaped URL silently ignores
// NO_PROXY hosts that the running session would bypass. Same
// comma-separated shape as the standard NO_PROXY env var.
NoProxy string
}
EgressProbeOptions controls one egress probe. Zero value uses defaults (5s timeout; target resolved from env or hardcoded default).
type EgressProbeResult ¶
type EgressProbeResult struct {
Profile string `json:"profile"`
Status ProbeStatus `json:"status"`
Latency time.Duration `json:"-"` // serialized via LatencyMs below
// LatencyMs is always serialized — 0 is a real value (sub-ms probe
// or early-failure latency before network), not "missing". Dropping
// the field with omitempty would conflate a successful fast probe
// with a probe that never started; both surfaces (CLI + popover)
// would render "—" for an OK result, which users read as broken.
LatencyMs int64 `json:"latency_ms"`
Target string `json:"target"` // URL actually probed
EgressVia string `json:"egress_via"` // sanitized (no userinfo)
HTTPStatus int `json:"http_status,omitempty"`
// From ipinfo response body (best-effort parse on OK)
PublicIP string `json:"public_ip,omitempty"`
Country string `json:"country,omitempty"`
Region string `json:"region,omitempty"`
City string `json:"city,omitempty"`
Org string `json:"org,omitempty"`
Err string `json:"err,omitempty"`
}
EgressProbeResult is what one egress probe returns. Status reuses ProbeStatus from probe.go so consumer switch statements stay uniform; only OK / TIMEOUT / NET_FAIL / HTTP_4XX / HTTP_5XX are actually emitted (SKIPPED / AUTH_FAIL / MODEL_404 are upstream-probe concepts and never appear here).
func ProbeEgress ¶
func ProbeEgress(profile profiles.Profile, opts EgressProbeOptions) EgressProbeResult
ProbeEgress runs one HTTPS GET against the resolved probe target, routed through profile.Egress. Result is always non-nil; never panics. Safe for concurrent use across different profiles.
Target resolution precedence:
- opts.Target (test / CLI --target)
- os.Getenv(envEgressTestTarget)
- defaultEgressTestTarget
Profile.Auth is intentionally ignored — egress probe sends NO credentials. profile.BaseURL is ignored too; the target is always the egress-test URL.
Treatment of profile.Egress.Mode:
- "direct" → no proxy (explicit bypass of env)
- "http" → HTTP CONNECT via profile.Egress.URL
- "socks5", "socks5h" → SOCKS via profile.Egress.URL
- "inherit" or unset → resolves through the calling process's environment via egress.Resolve (HTTPS_PROXY, HTTP_PROXY, ALL_PROXY, NO_PROXY). With no proxy env set, this is direct. With env set, the probe traverses that proxy — the same traffic-shape the caller would inherit at runtime. Callers wanting an explicit direct bypass must use mode="direct".
- anything else → same env-resolution path as inherit (forward-compat; unknown modes do not crash but they DO follow env, so they are not equivalent to "direct")
Latency and LatencyMs are both populated at every result-return point; callers should not need to derive one from the other.
func (EgressProbeResult) MarshalJSON ¶
func (r EgressProbeResult) MarshalJSON() ([]byte, error)
MarshalJSON renders Status as its string form (e.g. "OK", "NET_FAIL") so the wire schema exposes a stable string rather than the underlying int Go would serialize by default. Other fields use their tagged defaults. The Latency time.Duration is omitted from JSON via its `json:"-"` tag; LatencyMs is the wire-visible variant.
type ProbeOptions ¶
type ProbeOptions struct {
// Model, if non-empty, overrides the auto-resolved probe model.
// When set, alias rewriting is bypassed (the literal value goes
// into the request body's "model" field).
Model string
// Timeout caps the entire probe (DNS+connect+TLS+request+response).
Timeout time.Duration
}
ProbeOptions controls a single probe.
type ProbeResult ¶
type ProbeResult struct {
Profile string
Status ProbeStatus
Latency time.Duration
HTTPStatus int // 0 if no response
BaseURLHost string // host only, no userinfo
ModelSent string // the model field actually transmitted
ModelSentRewroteFrom string // empty unless alias rewrite happened
ModelEchoed string // upstream response body's model field
Err string // single-line summary
SkippedReason string // populated when Status == StatusSkipped
}
ProbeResult is what one probe returns.
func Probe ¶
func Probe(profile profiles.Profile, opts ProbeOptions) ProbeResult
Probe runs a single probe against one profile. The result is always non-nil and never panics. Callers may run Probe concurrently for different profiles.
A profile with no auth block (profile.Auth == nil) means "ccwrap does not own auth": there is no credential the probe can inject, so the probe short-circuits to SKIPPED, the same disposition as a passthrough profile.
type ProbeStatus ¶
type ProbeStatus int
ProbeStatus is the classified outcome of a single probe.
const ( StatusOK ProbeStatus = iota StatusSkipped StatusAuthFail StatusModel404 StatusHTTP4xx StatusHTTP5xx StatusTimeout StatusNetFail )
func (ProbeStatus) IsFailure ¶
func (s ProbeStatus) IsFailure() bool
IsFailure reports whether this status should contribute to a non-zero process exit code. OK and SKIPPED do not.
func (ProbeStatus) String ¶
func (s ProbeStatus) String() string