Skip to content

refactor(agent-core-v2): rebuild the model wire layer on the kosong architecture#1970

Merged
sailist merged 20 commits into
MoonshotAI:mainfrom
sailist:refactor/kosong-reapply
Jul 21, 2026
Merged

refactor(agent-core-v2): rebuild the model wire layer on the kosong architecture#1970
sailist merged 20 commits into
MoonshotAI:mainfrom
sailist:refactor/kosong-reapply

Conversation

@sailist

@sailist sailist commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Related Issue

No linked issue — this PR lands the long-running kosong refactor branch for the experimental v2 engine, developed internally. The problem statement is below.

Problem

The v2 engine's model wire layer had accreted into per-provider dialect classes with vendor-name gates sprinkled through engine code. Adding or fixing a provider meant copying adapter code and hunting down vendor checks outside the layer that owned them; request intent (prompt cache key, thinking effort, sampling) reached providers by cloning whole model objects; and a never-functional [platforms] config section plus a redundant provider.platformId field made credential resolution a three-way guessing game. Meanwhile the branch had drifted behind main, which deleted the /api/v2 RPC surface and added per-turn thinking_effort telemetry on the old skeleton.

What changed

1. Land the kosong layered wire architecture

  • L0 contract (kosong/contract/): provider-agnostic wire types — messages, tools, usage, errors, capabilities, request trace.
  • L1 protocol layer (kosong/protocol/): a trait-based protocol registry — declarative traits (auth, streaming, thinking, media) compose into per-protocol bases, replacing handwritten dialect classes.
  • Provider layer (kosong/provider/): per-protocol provider definitions as data, not code; Kimi is one composed definition among peers.
  • Model & catalog layers (kosong/model/): materialization, two-layer model → provider credential resolution, completion-budget folding, thinking-effort resolution, and a read-only catalog over the same materialization the runtime uses.

2. Migrate the engine and peripherals onto kosong

  • Engine callers (llmRequester, loop, profile) now drive a ModelRequester resolved from IModelCatalog; per-turn request intent flows as request parameters instead of cloned model objects. The old app/llmProtocol layer is deleted.
  • Vendor-name gates outside the kosong layer are removed; provider behavior lives in the protocol/provider definitions.
  • The vertexai protocol is folded into google-genai via providerOptions; the unused [platforms] config section and provider.platformId are removed.
  • agent-core (v1), kap-server, acp-adapter, klient and the v2 test harness are synced to the new architecture; v2 tests and harness migrated.

3. Model resolution inspection and connectivity ping

  • IModelCatalog.inspect reports the three raw config layers plus the resolved runtime view with per-field provenance (config / override / builtin / env / synthesized), and ping probes live endpoint connectivity — exposed for internal debugging tools (kimi-inspect's Model Catalog view).

4. Test coverage for provider edge behavior

  • An end-to-end invalid-input × provider matrix pins conversion-layer and error-translation behavior across OpenAI, composed Kimi, Anthropic and Google GenAI through the real pipeline against a local mock endpoint.
  • klient smoke probes cover the model-requester boundary (error wrapping) and the Kimi-only wire encoding of dynamic tool declarations; trailing undefined args are trimmed so server-side defaults are no longer defeated by null on the wire.

5. Merge main (transcript layer, /api/v2 removal, thinking_effort telemetry)

  • Adopted main's drop of the /api/v2 RPC surface: the klient http transport and the kap-server channel whitelist are gone; kimi-inspect keeps its Model Catalog view on the /api/v1/debug reflection surface and the unified transcript layer.
  • Re-applied main's per-turn thinking_effort telemetry on the kosong requester: prepareTurnConfig snapshots the turn's model/effort/system-prompt at the turn boundary so loop telemetry and every request in the turn share one configuration.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works (e2e invalid-input matrix, boundary smoke probes, migrated v2 suites; agent-core-v2 3669 tests, kap-server 655 tests green locally).
  • Ran gen-changesets skill, or this PR needs no changeset (4 changesets on the branch: kosong architecture as minor, abort-retryable / prompt-cache-key / model-inspection as patch).
  • Ran gen-docs skill, or this PR needs no doc update (v2 engine is experimental and not user-facing; no CLI behavior change).

@changeset-bot

changeset-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4c0ebad

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jul 20, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@4c0ebad
npx https://pkg.pr.new/@moonshot-ai/kimi-code@4c0ebad

commit: 4c0ebad

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 336c43e089

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

? this.contextSize.get().measured
: undefined,
});
const requester = this.modelCatalog.getRequester(resolved.modelAlias);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep the requester in the turn snapshot

When model/provider config changes after prepareTurnConfig() has cached a turn, later requests in that same turn still use the cached resolved params but this line re-resolves the ModelRequester from the live catalog. Since the catalog invalidates on model/provider changes, a multi-step turn can switch endpoints/capabilities mid-turn while telemetry and budget data remain from the old model; cache the requester/model in TurnRequestConfig as the previous model snapshot did.

Useful? React with 👍 / 👎.

Comment on lines +161 to +163
for (const [modelId, record] of Object.entries(models)) {
if (record.provider !== undefined && record.provider in excludedProviders) {
excludedModels[modelId] = record;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve providerId-bound static models during refresh

For a static provider whose models use the structured providerId key, this exclusion misses those models because it only checks record.provider. On the default startup/interval all-provider refresh, the static provider is hidden from the refresh host but its providerId-bound models are not merged back as excluded models, so the orchestrator's whole-section model write can drop the user's static model/default selection; match record.providerId ?? record.provider here.

Useful? React with 👍 / 👎.

sailist added 19 commits July 21, 2026 11:06
- merge the seven kimi trait modules into kimi.contrib.ts as two trait
  objects: kimiOpenAITrait (all native-transport hooks) and
  kimiAnthropicTrait (thinking only)
- move bases/* implementations into per-protocol directories (openai/,
  anthropic/, google-genai/) and rename openai.contrib.ts to
  openai-legacy.contrib.ts
- add per-directory index.ts registration barrels (import = registration)
  and exempt them in check-domain-layers.mjs alongside *.contrib.ts
- consolidate shared model types (ModelOverrides, CompletionBudgetConfig/Params,
  ResolvedModelAuthMaterial, ThinkingDefaults/ModelThinkingMetadata) into
  kosong/model/model.types.ts and drop modelOverrides.ts
- rename L2 request types to the ModelRequest* prefix: LLMEvent ->
  ModelRequestEvent, LLMRequestInput -> ModelRequestInput,
  LLMCallParams -> ModelRequestParams
- extract ModelRequestTiming to replace three duplicated copies of the
  stream-timing shape
- rename L3 llmRequester types with the Agent prefix to match
  IAgentLLMRequesterService (AgentLLMRequestOverrides/Finish/Task/Source/
  PartHandler/LogFields)
- delete the unused LLMRequestParams type
- merge IModelCatalogService's enumeration surface (listModels /
  listProviders / getProvider / setDefaultModel and the wire shapes) into
  IModelCatalog; delete kosong/catalog/modelCatalog.ts
- move the remote refresh path to the new IProviderDiscoveryService
  (discovery.ts + discoveryService.ts, renamed from
  catalog/modelCatalogService.ts)
- relocate configSection / errors to discoveryConfigSection.ts / errors.ts;
  DEFAULT_MODEL_SECTION now lives in kosong/model/model.ts
- drop the L3 catalog layer from check-domain-layers.mjs
- kap-server routes / refresh scheduler / channelRegistry follow the split;
  klient renames the contract modelCatalogService to modelResolver and adds
  providerDiscovery; kimi-inspect reads via IModelCatalog
- modelRequesterImpl: drop the streamedAnyPart backfill, onMessagePart
  already delivers every part
- tests: remove the app/modelCatalog and kosong/catalog suites, add the
  kosong/model catalog and discovery suites
- add trimTrailingUndefined helper so optional trailing args no longer
  cross the wire as null in http/ipc transports, which defeated
  server-side default parameters
- add model-requester-boundary smoke probe for ChatProvider error
  wrapping behavior against real config and a local stub
- add kimi-select-tools smoke probe verifying the kimi-only wire
  encoding of dynamic tool declarations
- extend smoke.ts with a models set/get/delete round-trip, catalog
  list assertions, and update AGENTS.md with the new scripts
Method-shorthand members on OpenAIChatCompletionsHooks tripped
typescript-eslint(unbound-method) at every extraction site
(`const hook = this._hooks?.convertMessage` and friends), failing the
repo-wide lint job. Every implementation is a plain closure composed by
openaiHooks.ts, so declare the members as function-typed properties,
which matches the actual semantics and clears the four errors.
- agent-core-v2: point vacuousContent's ContentPart import at kosong/contract
- kap-server: rewrite the transcript test seed as IModelCatalog (IModelResolver is gone)
- klient: inline onceEvent/waitFor after the http transport helpers were dropped
- kimi-inspect: remove useLiveEvent from ModelCatalogView; catalog polls on a slow interval
@sailist
sailist force-pushed the refactor/kosong-reapply branch from f5f309a to e9d2271 Compare July 21, 2026 03:46
@sailist
sailist merged commit 6dd4fd3 into MoonshotAI:main Jul 21, 2026
14 checks passed
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.

1 participant