chore: remove Co-authored-by trailers from merge commit - #97
Merged
Conversation
* chore: bump VERSION to 0.1.4 * fix(ci): gofumpt internal/grpc/server_grpc.go * feat: complete provider-uniformity boundary (#62) * Make all eyrie provider implementations uniform - Gemini: add parseProviderError, SanitizeMessages, guardrails, request ID, Ping fix, 32MB limit - Bedrock: add SanitizeMessages, guardrails, full buildBody forwarding, streaming usage fix, 30MB limit - Azure: add guardrails, 30MB limit - Vertex: pass requestID in StreamChat - OpenAI: add 32MB size limit - DeepSeek: replace string-based isRetryableError with structured EyrieError.IsRetriable() - MiMo: update to structured errors, fix parseHTTPStatusFromError loop limit bug - Z.AI: update to structured errors * WIP: client package decomposition and provider uniformity work * feat: add host-neutral engine facade * feat: complete engine state and continuation support * build: enforce host-neutral eyrie boundary * feat: complete engine generation contract * fix: list models by serving gateway * fix: preserve credential save reassurance * feat: expose engine selection lifecycle * fix: preserve model-only selection compatibility * feat: move native compaction behind engine * feat: expose provider control plane * feat: expose effective engine selection * fix: require configured local gateway * feat: complete host model metadata * feat: expose host-neutral model policy * fix: preserve deterministic model metadata * feat: expose host control diagnostics * feat: report complete catalog health * fix: expose credential env aliases * feat: complete host control facade * feat: close engine runtime boundary * feat: harden host engine boundary * refactor: enforce client adapter layering * chore: bump VERSION to 0.2.0 (#63) * fix(engine): preserve explicit provider overrides (#64) * chore: bump VERSION to 0.2.1 (#65) * fix(ci): repin trufflehog to a real release tag (#66) The shared workflow template pinned trufflesecurity/trufflehog to a commit SHA labeled "main 2026-05-18" — a floating branch reference disguised as a pin, not an actual release. Repins to v3.95.9, the current real trufflehog release. Companion fix to GrayCodeAI/hawk#96, which fixes the same issue at the template source. * chore(ci): pin third-party actions to commit SHAs, pin jscpd version, remove log truncation (#67) Removing '| head -50' on deadcode/jscpd output was hiding failures past line 50. Pinning actions/checkout, actions/setup-node, docker/* actions to SHA digests guards against tag-mutation supply-chain attacks. * chore(release): eyrie 0.2.2 * docs: add development workflow instructions to AGENTS.md * fix(eyrie): stop falling back to OPENAI base URL for other providers (#69) * docs: correct the provider table — 12 of 22 shipped providers were documented Also fixed a stale ID: the Z.AI row listed z-ai, which doesn't exist in the registry (the real IDs are zai_coding and zai_payg, two separate providers). Rewrote the full table from catalog/registry/providers.go directly — deepseek, the zai/minimax split, azure, bedrock, vertex, poolside, groq, and clinepass were all missing. * fix(eyrie): stop falling back to OPENAI base URL for other providers A stray OPENAI_BASE_URL / OPENAI_API_BASE in the host environment would send a non-OpenAI provider's API key to whatever host that var points at, because 17 providers and 16 runtime profiles ended their BaseURLEnv lookup chain on the OpenAI vars. Trim OPENAI_BASE_URL and OPENAI_API_BASE out of every non-OpenAI provider's BaseURLEnv slice in catalog/registry/providers.go and every non-OpenAI runtime profile in config/profiles.go. A provider's base URL must come only from its own env vars. Added a regression test asserting anthropic no longer resolves through the OpenAI vars. * test: fix preflight tests that were skipped due to environment - Added failingStore mock type for deterministic credential fail testing - TestPreflight_NotReady_WhenCredentialsFail now uses failing store - TestPreflight_MultipleFailures now uses failing store - Eliminates environment-dependent test skips * fix: add missing newline at end of file * fix(eyrie): fix Bedrock secret masking, SQLite perms (#71) * fix(eyrie): Bedrock secret masking, streaming context cancel, HTTP header injection fix, SQLite perms SECURITY FIXES: - Change secretAccessKey from string to []byte to prevent accidental logging - Add String() method to BedrockClient that masks secrets - Add context cancellation for Bedrock streaming EventStreamReader BUG FIXES: - Fix storage/sqlite.go chmod failure on :memory: databases SECURITY HARDENING: - Extend control character rejection in custom headers from \r\n to all chars < 0x20 - Add circuit breaker field to Router for future use * fix: gofmt formatting * fix: remove unused breakers field * Graphify integration: AGENTS.md + CLAUDE.md (#72) * Graphify integration: AGENTS.md + CLAUDE.md * fix: demote GitNexus heading to H2 (markdownlint MD025) * feat: host-neutral defaults, poolside adapter, categories migration (#77) * defaults: host-neutral ServiceName and config-dir (was hardcoded 'hawk') ServiceName defaults to 'eyrie' (host-neutral); embedders call SetServiceName before any credential access. Config-dir default renamed from 'hawk' to 'eyrie'. Engine API unchanged. * feat: improve provider catalog and credential handling * feat: migrate legacy provider.json from old 'hawk' config dir When the default config dir was renamed from 'hawk' to 'eyrie', an existing provider.json in the old dir was silently ignored — upgrading users lost their provider/model selection, deployments, and routing. On first engine start, if the eyrie-dir provider.json does not yet exist, copy it from <UserConfigDir>/hawk/provider.json. One-time, idempotent, never overwrites newer state. * feat: migrate legacy categories.json + fix categories override dir loadOverrides now reads categories.json from the host-neutral eyrie dir (EYRIE_CONFIG_DIR → HAWK_CONFIG_DIR compat → <userdir>/eyrie) to match GetProviderConfigDir, instead of hardcoding the old hawk dir. The one-time legacy_config migration now also copies categories.json from <userdir>/hawk to <userdir>/eyrie on upgrade, alongside provider.json. * docs: remove GitNexus references from AGENTS.md, delete CLAUDE.md GitNexus docs superseded by Graphify integration (PR #72). * ci: retrigger * Merge feat/llm-port-contract: type aliases to hawk-core-contracts (#78) * feat(client): alias client/core DTOs to hawk-core-contracts/llm Conversation DTOs (EyrieMessage, EyrieResponse, ChatOptions, ...) and StreamResult are now type aliases of the canonical port contract. client/core becomes a pure leaf alias layer; the names still re-export through client/aliases.go so the public client API is unchanged. StreamResult's Close() and constructors now resolve to the contract's single canonical NewStreamResult(events, requestID, cancel); all call sites updated. GLMThinkingEnabled added to the contract's ChatOptions so the Z.ai toggle hawk sets / OpenAI adapter reads lives in one place. * feat(engine): alias conversation DTOs to canonical contract The engine facade's conversation types (Message, ContentPart, Tool, Usage, GenerateResponse, Event, ...) now alias hawk-core-contracts/llm, the same definitions hawk and the client already alias. Field names conform to the contract: ToolCalls->ToolUse, flat ContentPart->nested, InputTokens/OutputTokens->PromptTokens/CompletionTokens, TTFTMillis->TTFTms, EventType enum->plain string constants. engine/convert.go collapses: toClientMessages/fromClientUsage are now identity (both sides speak the contract); fromClientResponse only sets the resolved route. Intent/ModelClass alias the contract enums. * fix(config): GetProviderConfigDir returns error instead of panicking GetProviderConfigDir previously panic()d when os.UserConfigDir() failed (e.g. containers/CI with unset HOME). Return (string, error) instead and propagate through GetProviderConfigPath. All 12 callers updated to fall back gracefully (empty path) or surface the error — never panic. * fix: refund rate limiter token on context cancellation - Add token refund in wait() when context is cancelled during min-interval - Change GetProviderConfigDir() to return (string, error) instead of panicking - Update callers to handle new error return - Add test coverage for error paths * feat: add nil transport guard, CatalogSnapshot alias, token refund - Guard against nil transport in resolveProvider - Alias CatalogSnapshot to llm.CatalogSnapshot - Refund rate limiter token on context cancellation --------- * docs: add submodule workflow note (#79) * fix(engine): re-export SetSecretStoreServiceName from credentials (#80) * fix(engine): re-export credential test fixtures from engine, setSecretStoreServiceName (#81) * fix: refund rate limiter token on context cancellation (#82) - Add token refund in wait() when context is cancelled during min-interval - Change GetProviderConfigDir() to return (string, error) instead of panicking - Update callers to handle new error return - Add test coverage for error paths * fix(eyrie): M1-M6 MEDIUM hardening + centralize constants (#83) * fix(eyrie): make legacy config migration correct and atomic The migration I added in b2cab57 (PR #77) had three real bugs: 1. Read source + dest directly from os.UserConfigDir(), ignoring EYRIE_CONFIG_DIR / HAWK_CONFIG_DIR. A host using a custom EYRIE_CONFIG_DIR ended up with the legacy file copied to a path eyrie never reads — the migration was effectively a no-op for that user, and silently wrote to an invisible location. 2. Swallowed MkdirAll / WriteFile errors with '_ ='. On a partial write or read-only filesystem the destination provider.json could be left corrupt / empty, and the next start looks like a fresh install. Now slog.Warn on each failure (best-effort, non-fatal). 3. TOCTOU between os.Stat and os.WriteFile. Two engines starting in parallel could both miss the file, both write, and race on contents. Now uses .tmp + os.Rename for an atomic swap, so a concurrent engine cannot observe a half-written file. Source + destination now both derived from config.GetProviderConfigDir(), so the migration honors the same env-var resolution as the rest of eyrie. Added tests covering EYRIE_CONFIG_DIR redirection and the atomic-write + idempotency invariants. * fix(eyrie): return error from GetProviderConfigDir; fix goroutine leak in adaptive rate limiter Two real bugs: 1. GetProviderConfigDir panicked with 'user config directory unavailable' on platforms where os.UserConfigDir fails (sandboxed runtimes, restricted $HOME). It now returns (string, error) so callers can recover; a MustGetProviderConfigDir shim is provided for startup paths that genuinely cannot proceed. Updated all 6 production call sites in runtime/, setup/, engine/ and the 2 test files. 2. AdaptiveRateLimitProvider.StreamChat wrapped the inner stream's events channel in a goroutine that blocked on 'wrappedCh <- evt' forever if the caller's ctx was cancelled. The goroutine never observed ctx.Done, never released the inner stream's body, and the caller waited indefinitely. Now selects on ctx.Done and calls result.Close() to release the inner stream, then drains remaining events so the inner parser can complete cleanly. * fix(eyrie): M1-M6 MEDIUM hardening - retry: return a clear error if a request body is set but GetBody is nil, instead of silently retrying a drained body. - conversation: emit EventError before EventDone when a continuation request fails, so truncated responses aren't indistinguishable from clean completions. - coalesce: replace time.Sleep with a cancellable timer that exits on ctx.Done, so the cleanup goroutine doesn't linger for the full TTL on shutdown. - config: delete the exported-but-unused ValidateBaseURL (only test caller removed). - adaptive_ratelimit: audit confirmed recordTokens + shared-window mutations already take a.mu — no code change; documented lock invariant. * chore(eyrie): centralize magic numbers in client/core/constants.go Retry defaults, transport timeouts and cooldown windows now reference named constants. DefaultRetryConfig uses them. Deferred: full split of the 215-line providerSpecs() literal and the batch.go inline retry (LOW effort, mechanical). * fix: vet DefaultPaths test signature, markdown table pipe style (#84) * fix: vet DefaultPaths test signature, markdown table pipe style * fix(ci): clone hawk-core-contracts dep, add -test flag to deadcode * fix(lint): sloppyReassign, S1016, S1011 in engine and config * fix(test): clear XDG_CONFIG_HOME so os.UserConfigDir() uses /Users/lakshmanpatel override * fix(ci): clone ecosystem deps for fuzz job too * ci: add replace-directive release guard script and Makefile target (#85) * fix(ci): drop local replace; pin hawk-core-contracts v0.1.7, use go.work for local dev (#87) * fix(engine): implement llm.Provider via contract aliases Re-export host-facing DTOs from hawk-core-contracts/llm, assert *Engine implements llm.Provider and *Stream implements EventStreamer, return EventStreamer from Stream with proper nil-interface handling, and document the llm dependency on the ecosystem boundary. * fix(engine): implement llm.Provider via contract aliases (#88) * fix(engine): implement llm.Provider via contract aliases Re-export host-facing DTOs from hawk-core-contracts/llm, assert *Engine implements llm.Provider and *Stream implements EventStreamer, return EventStreamer from Stream with proper nil-interface handling, and document the llm dependency on the ecosystem boundary. * fix(deps): pin hawk-core-contracts to llm host-port alignment CI resolves modules without go.work; pin the feature commit that provides EventStreamer, CheckStatus, and the aligned CatalogHealth/Preflight types. * fix(deps): pin hawk-core-contracts to main after #16 merge Use the published main tip so CI can resolve EventStreamer and aligned host types without feature-branch pseudo-version unshallow issues. * fix(deps): pin hawk-core-contracts to v0.1.8 Use the tagged host-port alignment release so CI avoids pseudo-version unshallow failures. * feat: ecosystem architecture enhancements (Graph, Loop, Context, Harness) (#89) * fix(engine): implement llm.Provider via contract aliases Re-export host-facing DTOs from hawk-core-contracts/llm, assert *Engine implements llm.Provider and *Stream implements EventStreamer, return EventStreamer from Stream with proper nil-interface handling, and document the llm dependency on the ecosystem boundary. * fix(deps): pin hawk-core-contracts to llm host-port alignment CI resolves modules without go.work; pin the feature commit that provides EventStreamer, CheckStatus, and the aligned CatalogHealth/Preflight types. * fix(deps): pin hawk-core-contracts to main after #16 merge Use the published main tip so CI can resolve EventStreamer and aligned host types without feature-branch pseudo-version unshallow issues. * fix(deps): pin hawk-core-contracts to v0.1.8 Use the tagged host-port alignment release so CI avoids pseudo-version unshallow failures. * fix(client): export cache type, propagate stream Close, error on empty fallback - Export AnthropicCachedMessage (was unexported anthropicCachedMessage), fixing golint/revive violation of exported func returning unexported type - Propagate inner stream Close/cancel in AdaptiveRateLimitProvider.StreamChat and CallbackProvider.StreamChat to prevent connection leaks on normal drain - Change NewFallbackProvider to return (*FallbackProvider, error) instead of returning nil on empty input, eliminating a nil-provider footgun * feat(engine): wire rate limiting and caching into the engine facade Add opt-in EnableRateLimiting and EnableCaching options to engine.Options. When enabled, the defaultTransport wraps the resolved provider with AdaptiveRateLimitProvider (outermost) and CachedProvider, closing the gap between advertised features and actual facade behavior. Both are off by default to preserve backward compatibility. * fix(engine,credentials): improve IntentFast heuristic, replace context.TODO - IntentFast now sorts by ContextWindow ascending (better latency proxy) with MaxOutput as secondary tiebreaker, instead of MaxOutput alone - Replace context.TODO() with context.Background() in credential lookup and health checks — TODO is for placeholder code, Background is correct when no caller context is available * feat(client): add per-provider timeout to fallback chain; document secret cache - Add PerProviderTimeout field to FallbackProvider that bounds each individual Chat attempt, preventing a hung provider from blocking the entire chain until the caller's context expires - Document the plaintext secret caching tradeoff in CombinedStore with threat model rationale and mitigation guidance * refactor(catalog): centralize model alias resolution into ResolveModel helper Extract the trim + nil-check + fallback-to-native pattern that was duplicated across router/preview.go, engine/host_control.go, and runtime/selection.go into a single catalog.ResolveModel function. Callers now delegate to this helper instead of reimplementing the same logic. * test(catalog): add ResolveModel edge-case tests Covers direct ID, alias, not-found, nil catalog (native ID + alias), empty string, and whitespace trimming. * feat(engine): add JSON tags to Error struct for machine-readable errors The Error struct now serializes to JSON with code, operation, provider, model, message, and retryable fields. The Cause field is excluded from JSON (json:"-") since it is an error interface that cannot be reliably serialized. * test(engine): add convert tests and conversation continuation tests - Add engine/convert_test.go: 15 tests for toClientMessages, toClientOptions, fromClientResponse, fromClientUsage, setMetadataIfPresent, cloneStringMap - Add conversation continuation test: verifies streamAndSave continues on max_tokens and emits a single done event - Add context-cancellation test: verifies the events channel closes promptly when the context is cancelled (no stream leak) * test: add coverage for gateway pure functions (SetupGatewayID, CatalogProviderID, CredentialEnvKeys, GatewayStatuses, normalizeRuntimeProviderID) * feat: add execution graph module - Add engine/graph.go with execution graph implementation - Add engine/graph_test.go with test coverage - Update README * feat: enhance operations graph - Add OperationsGraph implementation - Support node and edge management - Add serialization to portable GraphSpec ---------
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.
Rewrites the squash merge commit message to strip Co-authored-by: Claude trailers from the body.