Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions packages/headless/harbor/run-harness-ab.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -854,8 +854,8 @@ export function harnessMakaAgentEnv(benchmarkProfile, env = process.env) {
};
}

function harnessMeasuredTransport(agentId, provider) {
const protocol = providerProxyUsageProtocol(agentId, provider);
function harnessMeasuredTransport(agentId, provider, model) {
const protocol = providerProxyUsageProtocol(agentId, provider, undefined, model);
if (protocol === 'openai-chat-sse') return 'openai-chat';
if (protocol === 'openai-responses-sse') return 'openai-responses';
if (protocol === 'anthropic-sse') return 'anthropic-messages';
Expand DownExpand Up@@ -929,7 +929,7 @@ export function buildHarnessAbManifest({
config: {
adapter: harnessAgentImportPath('maka'),
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport('maka', execution.provider) }
? { transport: harnessMeasuredTransport('maka', execution.provider, execution.model) }
: {}),
// The runner hands every arm MAKA_SYSTEM_PROMPT, but only the Maka
// cell applies it; the native CLIs hash it into their execution
Expand DownExpand Up@@ -964,7 +964,13 @@ export function buildHarnessAbManifest({
adapter: harnessAgentImportPath(profile.id),
...profile.config,
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport(profile.id, execution.provider) }
? {
transport: harnessMeasuredTransport(
profile.id,
execution.provider,
execution.model,
),
}
: {}),
...(profile.id === 'codex' && runtimeProfile.provider === 'deepseek'
? { modelCatalogFingerprint: CODEX_DEEPSEEK_MODEL_CATALOG_FINGERPRINT }
Expand Down
44 changes: 44 additions & 0 deletions packages/headless/src/__tests__/harbor-task-runner.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -126,6 +126,50 @@ test('DeepSeek routes each CLI through its native wire protocol', () => {
assert.equal(harnessAgentImportPath('reasonix'), 'reasonix_agent:MakaReasonixAgent');
});

test('the Maka arm measures the wire its own runtime resolves, not the adapter kind', () => {
// deepseek-v4-flash routes through the Responses API (`openAiAdapterApiProtocol`),
// so a proxy parsing it as Chat SSE never sees `[DONE]`, marks every request
// `interrupted`, and the runner throws the whole graded cell away as infra.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-responses-sse',
);
// Same provider, a model that stays on Chat Completions.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v3.2'),
'openai-chat-sse',
);
// An advertised protocol wins only where the runtime's own connection carries
// one. For DeepSeek it does not: `connectionFromEnv` drops it, so the runtime
// dials Responses regardless and a proxy that honoured the override would be
// parsing a wire nobody is speaking — the same wrong number, reintroduced
// through this function's own input.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', 'openai-chat', 'deepseek-v4-flash'),
'openai-responses-sse',
);
// The two providers whose connections do carry an advertised protocol have
// their own explicit branches above, asserted separately.
// Competitors run their own CLI, so the Maka runtime says nothing about them.
assert.equal(
providerProxyUsageProtocol('reasonix', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-chat-sse',
);
// The catalog spelling resolves to the same wire as the one the runtime dials.
// `resolveModelRuntime` does not recognize the prefixed id, so a caller that
// forwarded it raw would silently get the Chat guess back — this fix's own
// API re-entering the bug it exists to close.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek/deepseek-v4-flash'),
'openai-responses-sse',
);
// And a caller with no model id at all gets an error, not the guess.
assert.throws(
() => providerProxyUsageProtocol('maka', 'deepseek'),
/the maka arm requires a model id/,
);
});

interface FakeOptions {
reward?: string;
cell?: HarborCellOutput | null;
Expand Down
6 changes: 5 additions & 1 deletion packages/headless/src/__tests__/harness-ab-cli.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -717,7 +717,11 @@ test('harness CLI freezes the synchronized DeepSeek three-way composition', asyn
manifest.arms.map(
(arm: { metadata?: { config?: { transport?: string } } }) => arm.metadata?.config?.transport,
),
['openai-chat', 'openai-responses', 'anthropic-messages'],
// The Maka arm records the wire its runtime actually dials: deepseek-v4-flash
// resolves to Responses, so a manifest claiming Chat here would describe a
// run that never happened — and the proxy parsing it that way measured none
// of it.
['openai-responses', 'openai-responses', 'anthropic-messages'],
);
assert.equal(manifest.maxConcurrentAttempts, 6);
assert.equal(
Expand Down
50 changes: 50 additions & 0 deletions packages/headless/src/__tests__/harness-ab-run.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -221,6 +221,56 @@ describe('runHarnessAbComparison', () => {
}
});

test('retries an infra-failed cell whose task id carries a dot', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-dotted-retry-'));
try {
const promptPath = join(dir, 'empty-system-prompt.txt');
await writeFile(promptPath, '', 'utf8');
let failingAttempts = 0;
const calls: string[] = [];
const failingArm = harnessArm('maka', calls);
failingArm.harborRunner = async () => {
failingAttempts += 1;
throw new Error('container failed after launch');
};
const input = {
runId: 'glm-harness-ab',
runRoot: dir,
resultsJsonlPath: join(dir, 'results.jsonl'),
systemPromptPath: promptPath,
resumeFingerprint: 'sha256:manifest',
evaluationTasks: [
{ id: 'install-windows-3.11', path: '/tasks/install-windows-3.11' },
{ id: 'plain', path: '/tasks/plain' },
],
arms: [failingArm, harnessArm('opencode', calls)] as const,
};

await runHarnessAbComparison(input);
assert.equal(failingAttempts, 2);

// The written round id normalizes the dot, so that is what an operator
// reads back out of results.jsonl and feeds to the retry.
await runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-install-windows-3-11'],
});
assert.equal(failingAttempts, 3);

// An operator recovering a sweep hands over a batch of ids. Naming only
// the first offender makes fixing a list of typos one round-trip each.
await assert.rejects(
runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-nope', 'ab-maka-r0-also-nope'],
}),
/unknown round ab-maka-r0-nope, ab-maka-r0-also-nope/,
);
} finally {
await rm(dir, { recursive: true, force: true });
}
});

test('continues the frozen schedule after a terminal cell infrastructure failure', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-resilient-schedule-'));
try {
Expand Down
9 changes: 3 additions & 6 deletions packages/headless/src/harbor-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,8 +49,10 @@ import {
type ProviderTokenUsage,
type ProviderUpstreamCredentialResolver,
} from './provider-auth-proxy.js';
export { modelIdForProvider } from './harness-agent-registry.js';
import {
harnessAgentImportPath,
modelIdForProvider,
providerProxyClientAuthMode,
providerProxyClientBaseUrl,
providerProxyUpstreamAuthMode,
Expand DownExpand Up@@ -1422,7 +1424,7 @@ async function hostSideProviderRuntime(options: HarborTaskRunnerOptions): Promis
: { apiKeyFile: apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
});
return {
env:
Expand DownExpand Up@@ -1909,11 +1911,6 @@ export function isBudgetExhaustedError(
* ("openai-compatible" routing "anthropic/claude-sonnet-4-5"). The cell's
* parseModelSpec preserves whatever it receives when a provider is set, so the
* stripping must happen here. */
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function modelForOpenCode(model: string, provider: string): string {
return model.includes('/') ? model : `${provider}/${model}`;
}
Expand Down
21 changes: 15 additions & 6 deletions packages/headless/src/harness-ab-run.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
import { buildRunManifestFingerprint } from './ab-manifest.js';
import { runArmCohort } from './ab-run.js';
import { buildAbRoundId, runArmCohort } from './ab-run.js';
import { withAbRunLock } from './ab-run-lock.js';
import type { AbComparisonSummary, ArmCohortResult } from './ab-types.js';
import { isEvaluatedOutcome, summarizeAbComparison } from './ab-summary.js';
Expand DownExpand Up@@ -142,13 +142,22 @@ async function executeHarnessArmCohort(input: RunHarnessArmCohortInput): Promise
if (retryRoundIds.size !== (input.retryAdjudicatedInfraRoundIdsOnce?.length ?? 0)) {
throw new Error('adjudicated infra retry round ids must be unique');
}
// Build the candidates with the same helper the cohort writes with. Spelling
// the id out here instead let the two drift: `buildAbRoundId` normalizes `.`
// to `-`, so a retry naming `install-windows-3.11` was rejected as unknown —
// and because the check throws rather than skips, one dotted task took the
// whole retry batch down with it.
const validRoundIds = new Set(
input.evaluationTasks.flatMap((task) => input.arms.map((arm) => `ab-${arm.id}-r0-${task.id}`)),
input.evaluationTasks.flatMap((task) =>
input.arms.map((arm) => buildAbRoundId(undefined, arm.id, 0, task.id)),
),
);
for (const roundId of retryRoundIds) {
if (!validRoundIds.has(roundId)) {
throw new Error(`adjudicated infra retry names unknown round ${roundId}`);
}
// Report every unknown id at once. An operator recovering a sweep hands over
// a batch of them, and failing on the first turns one typo into as many
// round-trips as there are mistakes.
const unknownRoundIds = [...retryRoundIds].filter((roundId) => !validRoundIds.has(roundId));
if (unknownRoundIds.length > 0) {
throw new Error(`adjudicated infra retry names unknown round ${unknownRoundIds.join(', ')}`);
}
const preexistingEventIds = new Set(
(await readFixedPromptWal(input.resultsJsonlPath))
Expand Down
64 changes: 63 additions & 1 deletion packages/headless/src/harness-agent-registry.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
import { PROVIDER_DEFAULTS, type ProviderType } from '@maka/core/llm-connections';
import { PROVIDER_DEFAULTS, type ModelInfo, type ProviderType } from '@maka/core/llm-connections';
import { type ModelRuntimeWire, resolveModelRuntime } from '@maka/runtime/model-runtime';
import type { ProviderAuthProxyMode, ProviderUsageProtocol } from './provider-auth-proxy.js';
import { modelApiProtocolFromEnv, selectedModelApiProtocol } from './provider-env.js';

export type HarnessAgentId =
| 'maka'
Expand DownExpand Up@@ -68,23 +70,83 @@ export function providerProxyUpstreamAuthMode(
: 'bearer';
}

/**
* The model id as the provider itself spells it, with the catalog's `provider/`
* prefix removed. This is what the runtime dials with, so it is also the only
* spelling any provider-facing decision may be made on.
*/
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function providerProxyUsageProtocol(
agent: HarnessAgentId,
provider: string,
apiProtocol?: string,
modelId?: string,
): ProviderUsageProtocol | undefined {
if (agent === 'codex') return 'openai-responses-sse';
if (agent === 'claude-code') return 'anthropic-sse';
if (agent === 'kimi-code') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'openai-chat') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'anthropic-messages')
return 'anthropic-sse';
// The Maka arm dials whatever wire its own runtime resolves, so that runtime
// is the authority here — the adapter kind is a guess, and a guess that
// drifts is not a gap but a wrong number: when deepseek-v4-flash moved to
// Responses, a proxy still parsing Chat SSE never saw `[DONE]`, recorded
// every request `interrupted` with no usage, and the runner threw each
// graded cell away as an infra failure.
//
// Which model is not optional information for the Maka arm: without it there
// is nothing to ask the runtime and the answer silently degrades back to the
// guess. Say so rather than returning a plausible wrong number. The id is
// normalized here so a caller passing the catalog spelling cannot resolve a
// different wire than the one the runtime dials — `resolveModelRuntime`
// does not recognize `deepseek/deepseek-v4-flash` and falls back to Chat.
if (agent === 'maka') {
if (!modelId) throw new Error('providerProxyUsageProtocol: the maka arm requires a model id');
const wire = makaRuntimeWire(provider, modelIdForProvider(modelId, provider), apiProtocol);
if (wire) return usageProtocolForWire(wire);
}
const definition = providerDefinition(provider);
if (definition?.runtimeAdapter.kind === 'anthropic') return 'anthropic-sse';
if (definition?.runtimeAdapter.kind === 'openai-compatible') return 'openai-chat-sse';
return undefined;
}

function makaRuntimeWire(
provider: string,
modelId: string,
apiProtocol?: string,
): ModelRuntimeWire | null {
if (!providerDefinition(provider)) return null;
// The connection the runtime will actually build, not one this side invents:
// an advertised protocol only reaches the model entry for the providers whose
// connections carry it, and `selectedModelApiProtocol` is where that is
// decided. Honouring it here where the runtime drops it would resolve a wire
// nothing dials — the wrong-number failure this whole path exists to remove.
const advertised = selectedModelApiProtocol(
provider as ProviderType,
modelApiProtocolFromEnv(apiProtocol),
);
return resolveModelRuntime(
{
providerType: provider as ProviderType,
...(advertised ? { models: [{ id: modelId, apiProtocol: advertised }] } : {}),
},
modelId,
).wire;
}

function usageProtocolForWire(wire: ModelRuntimeWire): ProviderUsageProtocol | undefined {
if (wire === 'anthropic-messages') return 'anthropic-sse';
if (wire === 'openai-chat') return 'openai-chat-sse';
if (wire === 'openai-responses') return 'openai-responses-sse';
return undefined;
}

function providerDefinition(provider: string) {
return (PROVIDER_DEFAULTS as Partial<Record<string, (typeof PROVIDER_DEFAULTS)[ProviderType]>>)[
provider
Expand Down
2 changes: 1 addition & 1 deletion packages/headless/src/pier-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -915,7 +915,7 @@ async function pierProviderRuntime(
: { apiKeyFile: options.apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
};
const proxy =
options.providerProxyHub && proxyPort !== undefined
Expand Down
27 changes: 24 additions & 3 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,28 @@ import {
} from '@maka/core';
import type { RunHarborCellEnv } from './headless-run-env.js';

/**
* The protocol a connection actually carries, given what was advertised.
*
* Only two providers let an advertised protocol pick the wire: GitHub Copilot,
* where the account discovers it, and the Kimi Coding Plan, which is sold as
* two protocols against one account. Everywhere else the model's own catalog
* entry decides, and an advertised value is dropped.
*
* Anything deciding what wire the Maka runtime will dial has to apply this same
* rule, or it decides about a connection the runtime will never build. The
* proxy resolves its SSE parser that way (`providerProxyUsageProtocol`), and
* honouring the override where the runtime drops it is the same wrong-wire
* failure — a proxy parsing Chat while the runtime dials Responses records
* every request interrupted with no usage.
*/
export function selectedModelApiProtocol(
provider: ProviderType,
advertised: ModelInfo['apiProtocol'],
): ModelInfo['apiProtocol'] {
return provider === 'github-copilot' || provider === 'kimi-coding-plan' ? advertised : undefined;
}

export interface ProviderCredentialEnv {
apiKeys: readonly string[];
apiKeyFile: string;
Expand DownExpand Up@@ -218,8 +240,7 @@ function connectionFromEnv(
if (provider === 'github-copilot' && !modelApiProtocol) {
throw new Error('GitHub Copilot requires an account-discovered model protocol');
}
const selectedApiProtocol =
provider === 'github-copilot' || provider === 'kimi-coding-plan' ? modelApiProtocol : undefined;
const selectedApiProtocol = selectedModelApiProtocol(provider, modelApiProtocol);
return {
slug: values.MAKA_LLM_CONNECTION_SLUG ?? provider,
name: defaults.label,
Expand All@@ -237,7 +258,7 @@ function connectionFromEnv(
};
}

function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
export function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
if (value === 'openai-chat' || value === 'openai-responses' || value === 'anthropic-messages')
return value;
return undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
"./tool-output-delta": "./dist/tool-output-delta.js",
"./stream-watchdog": "./dist/stream-watchdog.js",
"./model-factory": "./dist/model-factory.js",
"./model-runtime": "./dist/model-runtime.js",
"./context-budget": "./dist/context-budget.js",
"./active-full-compact": "./dist/active-full-compact.js",
"./semantic-compact": "./dist/semantic-compact.js",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions packages/headless/harbor/run-harness-ab.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -854,8 +854,8 @@ export function harnessMakaAgentEnv(benchmarkProfile, env = process.env) {
};
}

function harnessMeasuredTransport(agentId, provider) {
const protocol = providerProxyUsageProtocol(agentId, provider);
function harnessMeasuredTransport(agentId, provider, model) {
const protocol = providerProxyUsageProtocol(agentId, provider, undefined, model);
if (protocol === 'openai-chat-sse') return 'openai-chat';
if (protocol === 'openai-responses-sse') return 'openai-responses';
if (protocol === 'anthropic-sse') return 'anthropic-messages';
Expand DownExpand Up@@ -929,7 +929,7 @@ export function buildHarnessAbManifest({
config: {
adapter: harnessAgentImportPath('maka'),
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport('maka', execution.provider) }
? { transport: harnessMeasuredTransport('maka', execution.provider, execution.model) }
: {}),
// The runner hands every arm MAKA_SYSTEM_PROMPT, but only the Maka
// cell applies it; the native CLIs hash it into their execution
Expand DownExpand Up@@ -964,7 +964,13 @@ export function buildHarnessAbManifest({
adapter: harnessAgentImportPath(profile.id),
...profile.config,
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport(profile.id, execution.provider) }
? {
transport: harnessMeasuredTransport(
profile.id,
execution.provider,
execution.model,
),
}
: {}),
...(profile.id === 'codex' && runtimeProfile.provider === 'deepseek'
? { modelCatalogFingerprint: CODEX_DEEPSEEK_MODEL_CATALOG_FINGERPRINT }
Expand Down
44 changes: 44 additions & 0 deletions packages/headless/src/__tests__/harbor-task-runner.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -126,6 +126,50 @@ test('DeepSeek routes each CLI through its native wire protocol', () => {
assert.equal(harnessAgentImportPath('reasonix'), 'reasonix_agent:MakaReasonixAgent');
});

test('the Maka arm measures the wire its own runtime resolves, not the adapter kind', () => {
// deepseek-v4-flash routes through the Responses API (`openAiAdapterApiProtocol`),
// so a proxy parsing it as Chat SSE never sees `[DONE]`, marks every request
// `interrupted`, and the runner throws the whole graded cell away as infra.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-responses-sse',
);
// Same provider, a model that stays on Chat Completions.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v3.2'),
'openai-chat-sse',
);
// An advertised protocol wins only where the runtime's own connection carries
// one. For DeepSeek it does not: `connectionFromEnv` drops it, so the runtime
// dials Responses regardless and a proxy that honoured the override would be
// parsing a wire nobody is speaking — the same wrong number, reintroduced
// through this function's own input.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', 'openai-chat', 'deepseek-v4-flash'),
'openai-responses-sse',
);
// The two providers whose connections do carry an advertised protocol have
// their own explicit branches above, asserted separately.
// Competitors run their own CLI, so the Maka runtime says nothing about them.
assert.equal(
providerProxyUsageProtocol('reasonix', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-chat-sse',
);
// The catalog spelling resolves to the same wire as the one the runtime dials.
// `resolveModelRuntime` does not recognize the prefixed id, so a caller that
// forwarded it raw would silently get the Chat guess back — this fix's own
// API re-entering the bug it exists to close.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek/deepseek-v4-flash'),
'openai-responses-sse',
);
// And a caller with no model id at all gets an error, not the guess.
assert.throws(
() => providerProxyUsageProtocol('maka', 'deepseek'),
/the maka arm requires a model id/,
);
});

interface FakeOptions {
reward?: string;
cell?: HarborCellOutput | null;
Expand Down
6 changes: 5 additions & 1 deletion packages/headless/src/__tests__/harness-ab-cli.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -717,7 +717,11 @@ test('harness CLI freezes the synchronized DeepSeek three-way composition', asyn
manifest.arms.map(
(arm: { metadata?: { config?: { transport?: string } } }) => arm.metadata?.config?.transport,
),
['openai-chat', 'openai-responses', 'anthropic-messages'],
// The Maka arm records the wire its runtime actually dials: deepseek-v4-flash
// resolves to Responses, so a manifest claiming Chat here would describe a
// run that never happened — and the proxy parsing it that way measured none
// of it.
['openai-responses', 'openai-responses', 'anthropic-messages'],
);
assert.equal(manifest.maxConcurrentAttempts, 6);
assert.equal(
Expand Down
50 changes: 50 additions & 0 deletions packages/headless/src/__tests__/harness-ab-run.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -221,6 +221,56 @@ describe('runHarnessAbComparison', () => {
}
});

test('retries an infra-failed cell whose task id carries a dot', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-dotted-retry-'));
try {
const promptPath = join(dir, 'empty-system-prompt.txt');
await writeFile(promptPath, '', 'utf8');
let failingAttempts = 0;
const calls: string[] = [];
const failingArm = harnessArm('maka', calls);
failingArm.harborRunner = async () => {
failingAttempts += 1;
throw new Error('container failed after launch');
};
const input = {
runId: 'glm-harness-ab',
runRoot: dir,
resultsJsonlPath: join(dir, 'results.jsonl'),
systemPromptPath: promptPath,
resumeFingerprint: 'sha256:manifest',
evaluationTasks: [
{ id: 'install-windows-3.11', path: '/tasks/install-windows-3.11' },
{ id: 'plain', path: '/tasks/plain' },
],
arms: [failingArm, harnessArm('opencode', calls)] as const,
};

await runHarnessAbComparison(input);
assert.equal(failingAttempts, 2);

// The written round id normalizes the dot, so that is what an operator
// reads back out of results.jsonl and feeds to the retry.
await runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-install-windows-3-11'],
});
assert.equal(failingAttempts, 3);

// An operator recovering a sweep hands over a batch of ids. Naming only
// the first offender makes fixing a list of typos one round-trip each.
await assert.rejects(
runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-nope', 'ab-maka-r0-also-nope'],
}),
/unknown round ab-maka-r0-nope, ab-maka-r0-also-nope/,
);
} finally {
await rm(dir, { recursive: true, force: true });
}
});

test('continues the frozen schedule after a terminal cell infrastructure failure', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-resilient-schedule-'));
try {
Expand Down
9 changes: 3 additions & 6 deletions packages/headless/src/harbor-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,8 +49,10 @@ import {
type ProviderTokenUsage,
type ProviderUpstreamCredentialResolver,
} from './provider-auth-proxy.js';
export { modelIdForProvider } from './harness-agent-registry.js';
import {
harnessAgentImportPath,
modelIdForProvider,
providerProxyClientAuthMode,
providerProxyClientBaseUrl,
providerProxyUpstreamAuthMode,
Expand DownExpand Up@@ -1422,7 +1424,7 @@ async function hostSideProviderRuntime(options: HarborTaskRunnerOptions): Promis
: { apiKeyFile: apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
});
return {
env:
Expand DownExpand Up@@ -1909,11 +1911,6 @@ export function isBudgetExhaustedError(
* ("openai-compatible" routing "anthropic/claude-sonnet-4-5"). The cell's
* parseModelSpec preserves whatever it receives when a provider is set, so the
* stripping must happen here. */
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function modelForOpenCode(model: string, provider: string): string {
return model.includes('/') ? model : `${provider}/${model}`;
}
Expand Down
21 changes: 15 additions & 6 deletions packages/headless/src/harness-ab-run.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
import { buildRunManifestFingerprint } from './ab-manifest.js';
import { runArmCohort } from './ab-run.js';
import { buildAbRoundId, runArmCohort } from './ab-run.js';
import { withAbRunLock } from './ab-run-lock.js';
import type { AbComparisonSummary, ArmCohortResult } from './ab-types.js';
import { isEvaluatedOutcome, summarizeAbComparison } from './ab-summary.js';
Expand DownExpand Up@@ -142,13 +142,22 @@ async function executeHarnessArmCohort(input: RunHarnessArmCohortInput): Promise
if (retryRoundIds.size !== (input.retryAdjudicatedInfraRoundIdsOnce?.length ?? 0)) {
throw new Error('adjudicated infra retry round ids must be unique');
}
// Build the candidates with the same helper the cohort writes with. Spelling
// the id out here instead let the two drift: `buildAbRoundId` normalizes `.`
// to `-`, so a retry naming `install-windows-3.11` was rejected as unknown —
// and because the check throws rather than skips, one dotted task took the
// whole retry batch down with it.
const validRoundIds = new Set(
input.evaluationTasks.flatMap((task) => input.arms.map((arm) => `ab-${arm.id}-r0-${task.id}`)),
input.evaluationTasks.flatMap((task) =>
input.arms.map((arm) => buildAbRoundId(undefined, arm.id, 0, task.id)),
),
);
for (const roundId of retryRoundIds) {
if (!validRoundIds.has(roundId)) {
throw new Error(`adjudicated infra retry names unknown round ${roundId}`);
}
// Report every unknown id at once. An operator recovering a sweep hands over
// a batch of them, and failing on the first turns one typo into as many
// round-trips as there are mistakes.
const unknownRoundIds = [...retryRoundIds].filter((roundId) => !validRoundIds.has(roundId));
if (unknownRoundIds.length > 0) {
throw new Error(`adjudicated infra retry names unknown round ${unknownRoundIds.join(', ')}`);
}
const preexistingEventIds = new Set(
(await readFixedPromptWal(input.resultsJsonlPath))
Expand Down
64 changes: 63 additions & 1 deletion packages/headless/src/harness-agent-registry.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
import { PROVIDER_DEFAULTS, type ProviderType } from '@maka/core/llm-connections';
import { PROVIDER_DEFAULTS, type ModelInfo, type ProviderType } from '@maka/core/llm-connections';
import { type ModelRuntimeWire, resolveModelRuntime } from '@maka/runtime/model-runtime';
import type { ProviderAuthProxyMode, ProviderUsageProtocol } from './provider-auth-proxy.js';
import { modelApiProtocolFromEnv, selectedModelApiProtocol } from './provider-env.js';

export type HarnessAgentId =
| 'maka'
Expand DownExpand Up@@ -68,23 +70,83 @@ export function providerProxyUpstreamAuthMode(
: 'bearer';
}

/**
* The model id as the provider itself spells it, with the catalog's `provider/`
* prefix removed. This is what the runtime dials with, so it is also the only
* spelling any provider-facing decision may be made on.
*/
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function providerProxyUsageProtocol(
agent: HarnessAgentId,
provider: string,
apiProtocol?: string,
modelId?: string,
): ProviderUsageProtocol | undefined {
if (agent === 'codex') return 'openai-responses-sse';
if (agent === 'claude-code') return 'anthropic-sse';
if (agent === 'kimi-code') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'openai-chat') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'anthropic-messages')
return 'anthropic-sse';
// The Maka arm dials whatever wire its own runtime resolves, so that runtime
// is the authority here — the adapter kind is a guess, and a guess that
// drifts is not a gap but a wrong number: when deepseek-v4-flash moved to
// Responses, a proxy still parsing Chat SSE never saw `[DONE]`, recorded
// every request `interrupted` with no usage, and the runner threw each
// graded cell away as an infra failure.
//
// Which model is not optional information for the Maka arm: without it there
// is nothing to ask the runtime and the answer silently degrades back to the
// guess. Say so rather than returning a plausible wrong number. The id is
// normalized here so a caller passing the catalog spelling cannot resolve a
// different wire than the one the runtime dials — `resolveModelRuntime`
// does not recognize `deepseek/deepseek-v4-flash` and falls back to Chat.
if (agent === 'maka') {
if (!modelId) throw new Error('providerProxyUsageProtocol: the maka arm requires a model id');
const wire = makaRuntimeWire(provider, modelIdForProvider(modelId, provider), apiProtocol);
if (wire) return usageProtocolForWire(wire);
}
const definition = providerDefinition(provider);
if (definition?.runtimeAdapter.kind === 'anthropic') return 'anthropic-sse';
if (definition?.runtimeAdapter.kind === 'openai-compatible') return 'openai-chat-sse';
return undefined;
}

function makaRuntimeWire(
provider: string,
modelId: string,
apiProtocol?: string,
): ModelRuntimeWire | null {
if (!providerDefinition(provider)) return null;
// The connection the runtime will actually build, not one this side invents:
// an advertised protocol only reaches the model entry for the providers whose
// connections carry it, and `selectedModelApiProtocol` is where that is
// decided. Honouring it here where the runtime drops it would resolve a wire
// nothing dials — the wrong-number failure this whole path exists to remove.
const advertised = selectedModelApiProtocol(
provider as ProviderType,
modelApiProtocolFromEnv(apiProtocol),
);
return resolveModelRuntime(
{
providerType: provider as ProviderType,
...(advertised ? { models: [{ id: modelId, apiProtocol: advertised }] } : {}),
},
modelId,
).wire;
}

function usageProtocolForWire(wire: ModelRuntimeWire): ProviderUsageProtocol | undefined {
if (wire === 'anthropic-messages') return 'anthropic-sse';
if (wire === 'openai-chat') return 'openai-chat-sse';
if (wire === 'openai-responses') return 'openai-responses-sse';
return undefined;
}

function providerDefinition(provider: string) {
return (PROVIDER_DEFAULTS as Partial<Record<string, (typeof PROVIDER_DEFAULTS)[ProviderType]>>)[
provider
Expand Down
2 changes: 1 addition & 1 deletion packages/headless/src/pier-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -915,7 +915,7 @@ async function pierProviderRuntime(
: { apiKeyFile: options.apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
};
const proxy =
options.providerProxyHub && proxyPort !== undefined
Expand Down
27 changes: 24 additions & 3 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,28 @@ import {
} from '@maka/core';
import type { RunHarborCellEnv } from './headless-run-env.js';

/**
* The protocol a connection actually carries, given what was advertised.
*
* Only two providers let an advertised protocol pick the wire: GitHub Copilot,
* where the account discovers it, and the Kimi Coding Plan, which is sold as
* two protocols against one account. Everywhere else the model's own catalog
* entry decides, and an advertised value is dropped.
*
* Anything deciding what wire the Maka runtime will dial has to apply this same
* rule, or it decides about a connection the runtime will never build. The
* proxy resolves its SSE parser that way (`providerProxyUsageProtocol`), and
* honouring the override where the runtime drops it is the same wrong-wire
* failure — a proxy parsing Chat while the runtime dials Responses records
* every request interrupted with no usage.
*/
export function selectedModelApiProtocol(
provider: ProviderType,
advertised: ModelInfo['apiProtocol'],
): ModelInfo['apiProtocol'] {
return provider === 'github-copilot' || provider === 'kimi-coding-plan' ? advertised : undefined;
}

export interface ProviderCredentialEnv {
apiKeys: readonly string[];
apiKeyFile: string;
Expand DownExpand Up@@ -218,8 +240,7 @@ function connectionFromEnv(
if (provider === 'github-copilot' && !modelApiProtocol) {
throw new Error('GitHub Copilot requires an account-discovered model protocol');
}
const selectedApiProtocol =
provider === 'github-copilot' || provider === 'kimi-coding-plan' ? modelApiProtocol : undefined;
const selectedApiProtocol = selectedModelApiProtocol(provider, modelApiProtocol);
return {
slug: values.MAKA_LLM_CONNECTION_SLUG ?? provider,
name: defaults.label,
Expand All@@ -237,7 +258,7 @@ function connectionFromEnv(
};
}

function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
export function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
if (value === 'openai-chat' || value === 'openai-responses' || value === 'anthropic-messages')
return value;
return undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
"./tool-output-delta": "./dist/tool-output-delta.js",
"./stream-watchdog": "./dist/stream-watchdog.js",
"./model-factory": "./dist/model-factory.js",
"./model-runtime": "./dist/model-runtime.js",
"./context-budget": "./dist/context-budget.js",
"./active-full-compact": "./dist/active-full-compact.js",
"./semantic-compact": "./dist/semantic-compact.js",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions packages/headless/harbor/run-harness-ab.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -854,8 +854,8 @@ export function harnessMakaAgentEnv(benchmarkProfile, env = process.env) {
};
}

function harnessMeasuredTransport(agentId, provider) {
const protocol = providerProxyUsageProtocol(agentId, provider);
function harnessMeasuredTransport(agentId, provider, model) {
const protocol = providerProxyUsageProtocol(agentId, provider, undefined, model);
if (protocol === 'openai-chat-sse') return 'openai-chat';
if (protocol === 'openai-responses-sse') return 'openai-responses';
if (protocol === 'anthropic-sse') return 'anthropic-messages';
Expand DownExpand Up@@ -929,7 +929,7 @@ export function buildHarnessAbManifest({
config: {
adapter: harnessAgentImportPath('maka'),
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport('maka', execution.provider) }
? { transport: harnessMeasuredTransport('maka', execution.provider, execution.model) }
: {}),
// The runner hands every arm MAKA_SYSTEM_PROMPT, but only the Maka
// cell applies it; the native CLIs hash it into their execution
Expand DownExpand Up@@ -964,7 +964,13 @@ export function buildHarnessAbManifest({
adapter: harnessAgentImportPath(profile.id),
...profile.config,
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport(profile.id, execution.provider) }
? {
transport: harnessMeasuredTransport(
profile.id,
execution.provider,
execution.model,
),
}
: {}),
...(profile.id === 'codex' && runtimeProfile.provider === 'deepseek'
? { modelCatalogFingerprint: CODEX_DEEPSEEK_MODEL_CATALOG_FINGERPRINT }
Expand Down
44 changes: 44 additions & 0 deletions packages/headless/src/__tests__/harbor-task-runner.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -126,6 +126,50 @@ test('DeepSeek routes each CLI through its native wire protocol', () => {
assert.equal(harnessAgentImportPath('reasonix'), 'reasonix_agent:MakaReasonixAgent');
});

test('the Maka arm measures the wire its own runtime resolves, not the adapter kind', () => {
// deepseek-v4-flash routes through the Responses API (`openAiAdapterApiProtocol`),
// so a proxy parsing it as Chat SSE never sees `[DONE]`, marks every request
// `interrupted`, and the runner throws the whole graded cell away as infra.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-responses-sse',
);
// Same provider, a model that stays on Chat Completions.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v3.2'),
'openai-chat-sse',
);
// An advertised protocol wins only where the runtime's own connection carries
// one. For DeepSeek it does not: `connectionFromEnv` drops it, so the runtime
// dials Responses regardless and a proxy that honoured the override would be
// parsing a wire nobody is speaking — the same wrong number, reintroduced
// through this function's own input.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', 'openai-chat', 'deepseek-v4-flash'),
'openai-responses-sse',
);
// The two providers whose connections do carry an advertised protocol have
// their own explicit branches above, asserted separately.
// Competitors run their own CLI, so the Maka runtime says nothing about them.
assert.equal(
providerProxyUsageProtocol('reasonix', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-chat-sse',
);
// The catalog spelling resolves to the same wire as the one the runtime dials.
// `resolveModelRuntime` does not recognize the prefixed id, so a caller that
// forwarded it raw would silently get the Chat guess back — this fix's own
// API re-entering the bug it exists to close.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek/deepseek-v4-flash'),
'openai-responses-sse',
);
// And a caller with no model id at all gets an error, not the guess.
assert.throws(
() => providerProxyUsageProtocol('maka', 'deepseek'),
/the maka arm requires a model id/,
);
});

interface FakeOptions {
reward?: string;
cell?: HarborCellOutput | null;
Expand Down
6 changes: 5 additions & 1 deletion packages/headless/src/__tests__/harness-ab-cli.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -717,7 +717,11 @@ test('harness CLI freezes the synchronized DeepSeek three-way composition', asyn
manifest.arms.map(
(arm: { metadata?: { config?: { transport?: string } } }) => arm.metadata?.config?.transport,
),
['openai-chat', 'openai-responses', 'anthropic-messages'],
// The Maka arm records the wire its runtime actually dials: deepseek-v4-flash
// resolves to Responses, so a manifest claiming Chat here would describe a
// run that never happened — and the proxy parsing it that way measured none
// of it.
['openai-responses', 'openai-responses', 'anthropic-messages'],
);
assert.equal(manifest.maxConcurrentAttempts, 6);
assert.equal(
Expand Down
50 changes: 50 additions & 0 deletions packages/headless/src/__tests__/harness-ab-run.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -221,6 +221,56 @@ describe('runHarnessAbComparison', () => {
}
});

test('retries an infra-failed cell whose task id carries a dot', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-dotted-retry-'));
try {
const promptPath = join(dir, 'empty-system-prompt.txt');
await writeFile(promptPath, '', 'utf8');
let failingAttempts = 0;
const calls: string[] = [];
const failingArm = harnessArm('maka', calls);
failingArm.harborRunner = async () => {
failingAttempts += 1;
throw new Error('container failed after launch');
};
const input = {
runId: 'glm-harness-ab',
runRoot: dir,
resultsJsonlPath: join(dir, 'results.jsonl'),
systemPromptPath: promptPath,
resumeFingerprint: 'sha256:manifest',
evaluationTasks: [
{ id: 'install-windows-3.11', path: '/tasks/install-windows-3.11' },
{ id: 'plain', path: '/tasks/plain' },
],
arms: [failingArm, harnessArm('opencode', calls)] as const,
};

await runHarnessAbComparison(input);
assert.equal(failingAttempts, 2);

// The written round id normalizes the dot, so that is what an operator
// reads back out of results.jsonl and feeds to the retry.
await runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-install-windows-3-11'],
});
assert.equal(failingAttempts, 3);

// An operator recovering a sweep hands over a batch of ids. Naming only
// the first offender makes fixing a list of typos one round-trip each.
await assert.rejects(
runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-nope', 'ab-maka-r0-also-nope'],
}),
/unknown round ab-maka-r0-nope, ab-maka-r0-also-nope/,
);
} finally {
await rm(dir, { recursive: true, force: true });
}
});

test('continues the frozen schedule after a terminal cell infrastructure failure', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-resilient-schedule-'));
try {
Expand Down
9 changes: 3 additions & 6 deletions packages/headless/src/harbor-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,8 +49,10 @@ import {
type ProviderTokenUsage,
type ProviderUpstreamCredentialResolver,
} from './provider-auth-proxy.js';
export { modelIdForProvider } from './harness-agent-registry.js';
import {
harnessAgentImportPath,
modelIdForProvider,
providerProxyClientAuthMode,
providerProxyClientBaseUrl,
providerProxyUpstreamAuthMode,
Expand DownExpand Up@@ -1422,7 +1424,7 @@ async function hostSideProviderRuntime(options: HarborTaskRunnerOptions): Promis
: { apiKeyFile: apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
});
return {
env:
Expand DownExpand Up@@ -1909,11 +1911,6 @@ export function isBudgetExhaustedError(
* ("openai-compatible" routing "anthropic/claude-sonnet-4-5"). The cell's
* parseModelSpec preserves whatever it receives when a provider is set, so the
* stripping must happen here. */
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function modelForOpenCode(model: string, provider: string): string {
return model.includes('/') ? model : `${provider}/${model}`;
}
Expand Down
21 changes: 15 additions & 6 deletions packages/headless/src/harness-ab-run.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
import { buildRunManifestFingerprint } from './ab-manifest.js';
import { runArmCohort } from './ab-run.js';
import { buildAbRoundId, runArmCohort } from './ab-run.js';
import { withAbRunLock } from './ab-run-lock.js';
import type { AbComparisonSummary, ArmCohortResult } from './ab-types.js';
import { isEvaluatedOutcome, summarizeAbComparison } from './ab-summary.js';
Expand DownExpand Up@@ -142,13 +142,22 @@ async function executeHarnessArmCohort(input: RunHarnessArmCohortInput): Promise
if (retryRoundIds.size !== (input.retryAdjudicatedInfraRoundIdsOnce?.length ?? 0)) {
throw new Error('adjudicated infra retry round ids must be unique');
}
// Build the candidates with the same helper the cohort writes with. Spelling
// the id out here instead let the two drift: `buildAbRoundId` normalizes `.`
// to `-`, so a retry naming `install-windows-3.11` was rejected as unknown —
// and because the check throws rather than skips, one dotted task took the
// whole retry batch down with it.
const validRoundIds = new Set(
input.evaluationTasks.flatMap((task) => input.arms.map((arm) => `ab-${arm.id}-r0-${task.id}`)),
input.evaluationTasks.flatMap((task) =>
input.arms.map((arm) => buildAbRoundId(undefined, arm.id, 0, task.id)),
),
);
for (const roundId of retryRoundIds) {
if (!validRoundIds.has(roundId)) {
throw new Error(`adjudicated infra retry names unknown round ${roundId}`);
}
// Report every unknown id at once. An operator recovering a sweep hands over
// a batch of them, and failing on the first turns one typo into as many
// round-trips as there are mistakes.
const unknownRoundIds = [...retryRoundIds].filter((roundId) => !validRoundIds.has(roundId));
if (unknownRoundIds.length > 0) {
throw new Error(`adjudicated infra retry names unknown round ${unknownRoundIds.join(', ')}`);
}
const preexistingEventIds = new Set(
(await readFixedPromptWal(input.resultsJsonlPath))
Expand Down
64 changes: 63 additions & 1 deletion packages/headless/src/harness-agent-registry.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
import { PROVIDER_DEFAULTS, type ProviderType } from '@maka/core/llm-connections';
import { PROVIDER_DEFAULTS, type ModelInfo, type ProviderType } from '@maka/core/llm-connections';
import { type ModelRuntimeWire, resolveModelRuntime } from '@maka/runtime/model-runtime';
import type { ProviderAuthProxyMode, ProviderUsageProtocol } from './provider-auth-proxy.js';
import { modelApiProtocolFromEnv, selectedModelApiProtocol } from './provider-env.js';

export type HarnessAgentId =
| 'maka'
Expand DownExpand Up@@ -68,23 +70,83 @@ export function providerProxyUpstreamAuthMode(
: 'bearer';
}

/**
* The model id as the provider itself spells it, with the catalog's `provider/`
* prefix removed. This is what the runtime dials with, so it is also the only
* spelling any provider-facing decision may be made on.
*/
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function providerProxyUsageProtocol(
agent: HarnessAgentId,
provider: string,
apiProtocol?: string,
modelId?: string,
): ProviderUsageProtocol | undefined {
if (agent === 'codex') return 'openai-responses-sse';
if (agent === 'claude-code') return 'anthropic-sse';
if (agent === 'kimi-code') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'openai-chat') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'anthropic-messages')
return 'anthropic-sse';
// The Maka arm dials whatever wire its own runtime resolves, so that runtime
// is the authority here — the adapter kind is a guess, and a guess that
// drifts is not a gap but a wrong number: when deepseek-v4-flash moved to
// Responses, a proxy still parsing Chat SSE never saw `[DONE]`, recorded
// every request `interrupted` with no usage, and the runner threw each
// graded cell away as an infra failure.
//
// Which model is not optional information for the Maka arm: without it there
// is nothing to ask the runtime and the answer silently degrades back to the
// guess. Say so rather than returning a plausible wrong number. The id is
// normalized here so a caller passing the catalog spelling cannot resolve a
// different wire than the one the runtime dials — `resolveModelRuntime`
// does not recognize `deepseek/deepseek-v4-flash` and falls back to Chat.
if (agent === 'maka') {
if (!modelId) throw new Error('providerProxyUsageProtocol: the maka arm requires a model id');
const wire = makaRuntimeWire(provider, modelIdForProvider(modelId, provider), apiProtocol);
if (wire) return usageProtocolForWire(wire);
}
const definition = providerDefinition(provider);
if (definition?.runtimeAdapter.kind === 'anthropic') return 'anthropic-sse';
if (definition?.runtimeAdapter.kind === 'openai-compatible') return 'openai-chat-sse';
return undefined;
}

function makaRuntimeWire(
provider: string,
modelId: string,
apiProtocol?: string,
): ModelRuntimeWire | null {
if (!providerDefinition(provider)) return null;
// The connection the runtime will actually build, not one this side invents:
// an advertised protocol only reaches the model entry for the providers whose
// connections carry it, and `selectedModelApiProtocol` is where that is
// decided. Honouring it here where the runtime drops it would resolve a wire
// nothing dials — the wrong-number failure this whole path exists to remove.
const advertised = selectedModelApiProtocol(
provider as ProviderType,
modelApiProtocolFromEnv(apiProtocol),
);
return resolveModelRuntime(
{
providerType: provider as ProviderType,
...(advertised ? { models: [{ id: modelId, apiProtocol: advertised }] } : {}),
},
modelId,
).wire;
}

function usageProtocolForWire(wire: ModelRuntimeWire): ProviderUsageProtocol | undefined {
if (wire === 'anthropic-messages') return 'anthropic-sse';
if (wire === 'openai-chat') return 'openai-chat-sse';
if (wire === 'openai-responses') return 'openai-responses-sse';
return undefined;
}

function providerDefinition(provider: string) {
return (PROVIDER_DEFAULTS as Partial<Record<string, (typeof PROVIDER_DEFAULTS)[ProviderType]>>)[
provider
Expand Down
2 changes: 1 addition & 1 deletion packages/headless/src/pier-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -915,7 +915,7 @@ async function pierProviderRuntime(
: { apiKeyFile: options.apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
};
const proxy =
options.providerProxyHub && proxyPort !== undefined
Expand Down
27 changes: 24 additions & 3 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,28 @@ import {
} from '@maka/core';
import type { RunHarborCellEnv } from './headless-run-env.js';

/**
* The protocol a connection actually carries, given what was advertised.
*
* Only two providers let an advertised protocol pick the wire: GitHub Copilot,
* where the account discovers it, and the Kimi Coding Plan, which is sold as
* two protocols against one account. Everywhere else the model's own catalog
* entry decides, and an advertised value is dropped.
*
* Anything deciding what wire the Maka runtime will dial has to apply this same
* rule, or it decides about a connection the runtime will never build. The
* proxy resolves its SSE parser that way (`providerProxyUsageProtocol`), and
* honouring the override where the runtime drops it is the same wrong-wire
* failure — a proxy parsing Chat while the runtime dials Responses records
* every request interrupted with no usage.
*/
export function selectedModelApiProtocol(
provider: ProviderType,
advertised: ModelInfo['apiProtocol'],
): ModelInfo['apiProtocol'] {
return provider === 'github-copilot' || provider === 'kimi-coding-plan' ? advertised : undefined;
}

export interface ProviderCredentialEnv {
apiKeys: readonly string[];
apiKeyFile: string;
Expand DownExpand Up@@ -218,8 +240,7 @@ function connectionFromEnv(
if (provider === 'github-copilot' && !modelApiProtocol) {
throw new Error('GitHub Copilot requires an account-discovered model protocol');
}
const selectedApiProtocol =
provider === 'github-copilot' || provider === 'kimi-coding-plan' ? modelApiProtocol : undefined;
const selectedApiProtocol = selectedModelApiProtocol(provider, modelApiProtocol);
return {
slug: values.MAKA_LLM_CONNECTION_SLUG ?? provider,
name: defaults.label,
Expand All@@ -237,7 +258,7 @@ function connectionFromEnv(
};
}

function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
export function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
if (value === 'openai-chat' || value === 'openai-responses' || value === 'anthropic-messages')
return value;
return undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
"./tool-output-delta": "./dist/tool-output-delta.js",
"./stream-watchdog": "./dist/stream-watchdog.js",
"./model-factory": "./dist/model-factory.js",
"./model-runtime": "./dist/model-runtime.js",
"./context-budget": "./dist/context-budget.js",
"./active-full-compact": "./dist/active-full-compact.js",
"./semantic-compact": "./dist/semantic-compact.js",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions packages/headless/harbor/run-harness-ab.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -854,8 +854,8 @@ export function harnessMakaAgentEnv(benchmarkProfile, env = process.env) {
};
}

function harnessMeasuredTransport(agentId, provider) {
const protocol = providerProxyUsageProtocol(agentId, provider);
function harnessMeasuredTransport(agentId, provider, model) {
const protocol = providerProxyUsageProtocol(agentId, provider, undefined, model);
if (protocol === 'openai-chat-sse') return 'openai-chat';
if (protocol === 'openai-responses-sse') return 'openai-responses';
if (protocol === 'anthropic-sse') return 'anthropic-messages';
Expand DownExpand Up@@ -929,7 +929,7 @@ export function buildHarnessAbManifest({
config: {
adapter: harnessAgentImportPath('maka'),
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport('maka', execution.provider) }
? { transport: harnessMeasuredTransport('maka', execution.provider, execution.model) }
: {}),
// The runner hands every arm MAKA_SYSTEM_PROMPT, but only the Maka
// cell applies it; the native CLIs hash it into their execution
Expand DownExpand Up@@ -964,7 +964,13 @@ export function buildHarnessAbManifest({
adapter: harnessAgentImportPath(profile.id),
...profile.config,
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport(profile.id, execution.provider) }
? {
transport: harnessMeasuredTransport(
profile.id,
execution.provider,
execution.model,
),
}
: {}),
...(profile.id === 'codex' && runtimeProfile.provider === 'deepseek'
? { modelCatalogFingerprint: CODEX_DEEPSEEK_MODEL_CATALOG_FINGERPRINT }
Expand Down
44 changes: 44 additions & 0 deletions packages/headless/src/__tests__/harbor-task-runner.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -126,6 +126,50 @@ test('DeepSeek routes each CLI through its native wire protocol', () => {
assert.equal(harnessAgentImportPath('reasonix'), 'reasonix_agent:MakaReasonixAgent');
});

test('the Maka arm measures the wire its own runtime resolves, not the adapter kind', () => {
// deepseek-v4-flash routes through the Responses API (`openAiAdapterApiProtocol`),
// so a proxy parsing it as Chat SSE never sees `[DONE]`, marks every request
// `interrupted`, and the runner throws the whole graded cell away as infra.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-responses-sse',
);
// Same provider, a model that stays on Chat Completions.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v3.2'),
'openai-chat-sse',
);
// An advertised protocol wins only where the runtime's own connection carries
// one. For DeepSeek it does not: `connectionFromEnv` drops it, so the runtime
// dials Responses regardless and a proxy that honoured the override would be
// parsing a wire nobody is speaking — the same wrong number, reintroduced
// through this function's own input.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', 'openai-chat', 'deepseek-v4-flash'),
'openai-responses-sse',
);
// The two providers whose connections do carry an advertised protocol have
// their own explicit branches above, asserted separately.
// Competitors run their own CLI, so the Maka runtime says nothing about them.
assert.equal(
providerProxyUsageProtocol('reasonix', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-chat-sse',
);
// The catalog spelling resolves to the same wire as the one the runtime dials.
// `resolveModelRuntime` does not recognize the prefixed id, so a caller that
// forwarded it raw would silently get the Chat guess back — this fix's own
// API re-entering the bug it exists to close.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek/deepseek-v4-flash'),
'openai-responses-sse',
);
// And a caller with no model id at all gets an error, not the guess.
assert.throws(
() => providerProxyUsageProtocol('maka', 'deepseek'),
/the maka arm requires a model id/,
);
});

interface FakeOptions {
reward?: string;
cell?: HarborCellOutput | null;
Expand Down
6 changes: 5 additions & 1 deletion packages/headless/src/__tests__/harness-ab-cli.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -717,7 +717,11 @@ test('harness CLI freezes the synchronized DeepSeek three-way composition', asyn
manifest.arms.map(
(arm: { metadata?: { config?: { transport?: string } } }) => arm.metadata?.config?.transport,
),
['openai-chat', 'openai-responses', 'anthropic-messages'],
// The Maka arm records the wire its runtime actually dials: deepseek-v4-flash
// resolves to Responses, so a manifest claiming Chat here would describe a
// run that never happened — and the proxy parsing it that way measured none
// of it.
['openai-responses', 'openai-responses', 'anthropic-messages'],
);
assert.equal(manifest.maxConcurrentAttempts, 6);
assert.equal(
Expand Down
50 changes: 50 additions & 0 deletions packages/headless/src/__tests__/harness-ab-run.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -221,6 +221,56 @@ describe('runHarnessAbComparison', () => {
}
});

test('retries an infra-failed cell whose task id carries a dot', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-dotted-retry-'));
try {
const promptPath = join(dir, 'empty-system-prompt.txt');
await writeFile(promptPath, '', 'utf8');
let failingAttempts = 0;
const calls: string[] = [];
const failingArm = harnessArm('maka', calls);
failingArm.harborRunner = async () => {
failingAttempts += 1;
throw new Error('container failed after launch');
};
const input = {
runId: 'glm-harness-ab',
runRoot: dir,
resultsJsonlPath: join(dir, 'results.jsonl'),
systemPromptPath: promptPath,
resumeFingerprint: 'sha256:manifest',
evaluationTasks: [
{ id: 'install-windows-3.11', path: '/tasks/install-windows-3.11' },
{ id: 'plain', path: '/tasks/plain' },
],
arms: [failingArm, harnessArm('opencode', calls)] as const,
};

await runHarnessAbComparison(input);
assert.equal(failingAttempts, 2);

// The written round id normalizes the dot, so that is what an operator
// reads back out of results.jsonl and feeds to the retry.
await runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-install-windows-3-11'],
});
assert.equal(failingAttempts, 3);

// An operator recovering a sweep hands over a batch of ids. Naming only
// the first offender makes fixing a list of typos one round-trip each.
await assert.rejects(
runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-nope', 'ab-maka-r0-also-nope'],
}),
/unknown round ab-maka-r0-nope, ab-maka-r0-also-nope/,
);
} finally {
await rm(dir, { recursive: true, force: true });
}
});

test('continues the frozen schedule after a terminal cell infrastructure failure', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-resilient-schedule-'));
try {
Expand Down
9 changes: 3 additions & 6 deletions packages/headless/src/harbor-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,8 +49,10 @@ import {
type ProviderTokenUsage,
type ProviderUpstreamCredentialResolver,
} from './provider-auth-proxy.js';
export { modelIdForProvider } from './harness-agent-registry.js';
import {
harnessAgentImportPath,
modelIdForProvider,
providerProxyClientAuthMode,
providerProxyClientBaseUrl,
providerProxyUpstreamAuthMode,
Expand DownExpand Up@@ -1422,7 +1424,7 @@ async function hostSideProviderRuntime(options: HarborTaskRunnerOptions): Promis
: { apiKeyFile: apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
});
return {
env:
Expand DownExpand Up@@ -1909,11 +1911,6 @@ export function isBudgetExhaustedError(
* ("openai-compatible" routing "anthropic/claude-sonnet-4-5"). The cell's
* parseModelSpec preserves whatever it receives when a provider is set, so the
* stripping must happen here. */
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function modelForOpenCode(model: string, provider: string): string {
return model.includes('/') ? model : `${provider}/${model}`;
}
Expand Down
21 changes: 15 additions & 6 deletions packages/headless/src/harness-ab-run.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
import { buildRunManifestFingerprint } from './ab-manifest.js';
import { runArmCohort } from './ab-run.js';
import { buildAbRoundId, runArmCohort } from './ab-run.js';
import { withAbRunLock } from './ab-run-lock.js';
import type { AbComparisonSummary, ArmCohortResult } from './ab-types.js';
import { isEvaluatedOutcome, summarizeAbComparison } from './ab-summary.js';
Expand DownExpand Up@@ -142,13 +142,22 @@ async function executeHarnessArmCohort(input: RunHarnessArmCohortInput): Promise
if (retryRoundIds.size !== (input.retryAdjudicatedInfraRoundIdsOnce?.length ?? 0)) {
throw new Error('adjudicated infra retry round ids must be unique');
}
// Build the candidates with the same helper the cohort writes with. Spelling
// the id out here instead let the two drift: `buildAbRoundId` normalizes `.`
// to `-`, so a retry naming `install-windows-3.11` was rejected as unknown —
// and because the check throws rather than skips, one dotted task took the
// whole retry batch down with it.
const validRoundIds = new Set(
input.evaluationTasks.flatMap((task) => input.arms.map((arm) => `ab-${arm.id}-r0-${task.id}`)),
input.evaluationTasks.flatMap((task) =>
input.arms.map((arm) => buildAbRoundId(undefined, arm.id, 0, task.id)),
),
);
for (const roundId of retryRoundIds) {
if (!validRoundIds.has(roundId)) {
throw new Error(`adjudicated infra retry names unknown round ${roundId}`);
}
// Report every unknown id at once. An operator recovering a sweep hands over
// a batch of them, and failing on the first turns one typo into as many
// round-trips as there are mistakes.
const unknownRoundIds = [...retryRoundIds].filter((roundId) => !validRoundIds.has(roundId));
if (unknownRoundIds.length > 0) {
throw new Error(`adjudicated infra retry names unknown round ${unknownRoundIds.join(', ')}`);
}
const preexistingEventIds = new Set(
(await readFixedPromptWal(input.resultsJsonlPath))
Expand Down
64 changes: 63 additions & 1 deletion packages/headless/src/harness-agent-registry.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
import { PROVIDER_DEFAULTS, type ProviderType } from '@maka/core/llm-connections';
import { PROVIDER_DEFAULTS, type ModelInfo, type ProviderType } from '@maka/core/llm-connections';
import { type ModelRuntimeWire, resolveModelRuntime } from '@maka/runtime/model-runtime';
import type { ProviderAuthProxyMode, ProviderUsageProtocol } from './provider-auth-proxy.js';
import { modelApiProtocolFromEnv, selectedModelApiProtocol } from './provider-env.js';

export type HarnessAgentId =
| 'maka'
Expand DownExpand Up@@ -68,23 +70,83 @@ export function providerProxyUpstreamAuthMode(
: 'bearer';
}

/**
* The model id as the provider itself spells it, with the catalog's `provider/`
* prefix removed. This is what the runtime dials with, so it is also the only
* spelling any provider-facing decision may be made on.
*/
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function providerProxyUsageProtocol(
agent: HarnessAgentId,
provider: string,
apiProtocol?: string,
modelId?: string,
): ProviderUsageProtocol | undefined {
if (agent === 'codex') return 'openai-responses-sse';
if (agent === 'claude-code') return 'anthropic-sse';
if (agent === 'kimi-code') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'openai-chat') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'anthropic-messages')
return 'anthropic-sse';
// The Maka arm dials whatever wire its own runtime resolves, so that runtime
// is the authority here — the adapter kind is a guess, and a guess that
// drifts is not a gap but a wrong number: when deepseek-v4-flash moved to
// Responses, a proxy still parsing Chat SSE never saw `[DONE]`, recorded
// every request `interrupted` with no usage, and the runner threw each
// graded cell away as an infra failure.
//
// Which model is not optional information for the Maka arm: without it there
// is nothing to ask the runtime and the answer silently degrades back to the
// guess. Say so rather than returning a plausible wrong number. The id is
// normalized here so a caller passing the catalog spelling cannot resolve a
// different wire than the one the runtime dials — `resolveModelRuntime`
// does not recognize `deepseek/deepseek-v4-flash` and falls back to Chat.
if (agent === 'maka') {
if (!modelId) throw new Error('providerProxyUsageProtocol: the maka arm requires a model id');
const wire = makaRuntimeWire(provider, modelIdForProvider(modelId, provider), apiProtocol);
if (wire) return usageProtocolForWire(wire);
}
const definition = providerDefinition(provider);
if (definition?.runtimeAdapter.kind === 'anthropic') return 'anthropic-sse';
if (definition?.runtimeAdapter.kind === 'openai-compatible') return 'openai-chat-sse';
return undefined;
}

function makaRuntimeWire(
provider: string,
modelId: string,
apiProtocol?: string,
): ModelRuntimeWire | null {
if (!providerDefinition(provider)) return null;
// The connection the runtime will actually build, not one this side invents:
// an advertised protocol only reaches the model entry for the providers whose
// connections carry it, and `selectedModelApiProtocol` is where that is
// decided. Honouring it here where the runtime drops it would resolve a wire
// nothing dials — the wrong-number failure this whole path exists to remove.
const advertised = selectedModelApiProtocol(
provider as ProviderType,
modelApiProtocolFromEnv(apiProtocol),
);
return resolveModelRuntime(
{
providerType: provider as ProviderType,
...(advertised ? { models: [{ id: modelId, apiProtocol: advertised }] } : {}),
},
modelId,
).wire;
}

function usageProtocolForWire(wire: ModelRuntimeWire): ProviderUsageProtocol | undefined {
if (wire === 'anthropic-messages') return 'anthropic-sse';
if (wire === 'openai-chat') return 'openai-chat-sse';
if (wire === 'openai-responses') return 'openai-responses-sse';
return undefined;
}

function providerDefinition(provider: string) {
return (PROVIDER_DEFAULTS as Partial<Record<string, (typeof PROVIDER_DEFAULTS)[ProviderType]>>)[
provider
Expand Down
2 changes: 1 addition & 1 deletion packages/headless/src/pier-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -915,7 +915,7 @@ async function pierProviderRuntime(
: { apiKeyFile: options.apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
};
const proxy =
options.providerProxyHub && proxyPort !== undefined
Expand Down
27 changes: 24 additions & 3 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,28 @@ import {
} from '@maka/core';
import type { RunHarborCellEnv } from './headless-run-env.js';

/**
* The protocol a connection actually carries, given what was advertised.
*
* Only two providers let an advertised protocol pick the wire: GitHub Copilot,
* where the account discovers it, and the Kimi Coding Plan, which is sold as
* two protocols against one account. Everywhere else the model's own catalog
* entry decides, and an advertised value is dropped.
*
* Anything deciding what wire the Maka runtime will dial has to apply this same
* rule, or it decides about a connection the runtime will never build. The
* proxy resolves its SSE parser that way (`providerProxyUsageProtocol`), and
* honouring the override where the runtime drops it is the same wrong-wire
* failure — a proxy parsing Chat while the runtime dials Responses records
* every request interrupted with no usage.
*/
export function selectedModelApiProtocol(
provider: ProviderType,
advertised: ModelInfo['apiProtocol'],
): ModelInfo['apiProtocol'] {
return provider === 'github-copilot' || provider === 'kimi-coding-plan' ? advertised : undefined;
}

export interface ProviderCredentialEnv {
apiKeys: readonly string[];
apiKeyFile: string;
Expand DownExpand Up@@ -218,8 +240,7 @@ function connectionFromEnv(
if (provider === 'github-copilot' && !modelApiProtocol) {
throw new Error('GitHub Copilot requires an account-discovered model protocol');
}
const selectedApiProtocol =
provider === 'github-copilot' || provider === 'kimi-coding-plan' ? modelApiProtocol : undefined;
const selectedApiProtocol = selectedModelApiProtocol(provider, modelApiProtocol);
return {
slug: values.MAKA_LLM_CONNECTION_SLUG ?? provider,
name: defaults.label,
Expand All@@ -237,7 +258,7 @@ function connectionFromEnv(
};
}

function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
export function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
if (value === 'openai-chat' || value === 'openai-responses' || value === 'anthropic-messages')
return value;
return undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
"./tool-output-delta": "./dist/tool-output-delta.js",
"./stream-watchdog": "./dist/stream-watchdog.js",
"./model-factory": "./dist/model-factory.js",
"./model-runtime": "./dist/model-runtime.js",
"./context-budget": "./dist/context-budget.js",
"./active-full-compact": "./dist/active-full-compact.js",
"./semantic-compact": "./dist/semantic-compact.js",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions packages/headless/harbor/run-harness-ab.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -854,8 +854,8 @@ export function harnessMakaAgentEnv(benchmarkProfile, env = process.env) {
};
}

function harnessMeasuredTransport(agentId, provider) {
const protocol = providerProxyUsageProtocol(agentId, provider);
function harnessMeasuredTransport(agentId, provider, model) {
const protocol = providerProxyUsageProtocol(agentId, provider, undefined, model);
if (protocol === 'openai-chat-sse') return 'openai-chat';
if (protocol === 'openai-responses-sse') return 'openai-responses';
if (protocol === 'anthropic-sse') return 'anthropic-messages';
Expand DownExpand Up@@ -929,7 +929,7 @@ export function buildHarnessAbManifest({
config: {
adapter: harnessAgentImportPath('maka'),
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport('maka', execution.provider) }
? { transport: harnessMeasuredTransport('maka', execution.provider, execution.model) }
: {}),
// The runner hands every arm MAKA_SYSTEM_PROMPT, but only the Maka
// cell applies it; the native CLIs hash it into their execution
Expand DownExpand Up@@ -964,7 +964,13 @@ export function buildHarnessAbManifest({
adapter: harnessAgentImportPath(profile.id),
...profile.config,
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport(profile.id, execution.provider) }
? {
transport: harnessMeasuredTransport(
profile.id,
execution.provider,
execution.model,
),
}
: {}),
...(profile.id === 'codex' && runtimeProfile.provider === 'deepseek'
? { modelCatalogFingerprint: CODEX_DEEPSEEK_MODEL_CATALOG_FINGERPRINT }
Expand Down
44 changes: 44 additions & 0 deletions packages/headless/src/__tests__/harbor-task-runner.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -126,6 +126,50 @@ test('DeepSeek routes each CLI through its native wire protocol', () => {
assert.equal(harnessAgentImportPath('reasonix'), 'reasonix_agent:MakaReasonixAgent');
});

test('the Maka arm measures the wire its own runtime resolves, not the adapter kind', () => {
// deepseek-v4-flash routes through the Responses API (`openAiAdapterApiProtocol`),
// so a proxy parsing it as Chat SSE never sees `[DONE]`, marks every request
// `interrupted`, and the runner throws the whole graded cell away as infra.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-responses-sse',
);
// Same provider, a model that stays on Chat Completions.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v3.2'),
'openai-chat-sse',
);
// An advertised protocol wins only where the runtime's own connection carries
// one. For DeepSeek it does not: `connectionFromEnv` drops it, so the runtime
// dials Responses regardless and a proxy that honoured the override would be
// parsing a wire nobody is speaking — the same wrong number, reintroduced
// through this function's own input.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', 'openai-chat', 'deepseek-v4-flash'),
'openai-responses-sse',
);
// The two providers whose connections do carry an advertised protocol have
// their own explicit branches above, asserted separately.
// Competitors run their own CLI, so the Maka runtime says nothing about them.
assert.equal(
providerProxyUsageProtocol('reasonix', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-chat-sse',
);
// The catalog spelling resolves to the same wire as the one the runtime dials.
// `resolveModelRuntime` does not recognize the prefixed id, so a caller that
// forwarded it raw would silently get the Chat guess back — this fix's own
// API re-entering the bug it exists to close.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek/deepseek-v4-flash'),
'openai-responses-sse',
);
// And a caller with no model id at all gets an error, not the guess.
assert.throws(
() => providerProxyUsageProtocol('maka', 'deepseek'),
/the maka arm requires a model id/,
);
});

interface FakeOptions {
reward?: string;
cell?: HarborCellOutput | null;
Expand Down
6 changes: 5 additions & 1 deletion packages/headless/src/__tests__/harness-ab-cli.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -717,7 +717,11 @@ test('harness CLI freezes the synchronized DeepSeek three-way composition', asyn
manifest.arms.map(
(arm: { metadata?: { config?: { transport?: string } } }) => arm.metadata?.config?.transport,
),
['openai-chat', 'openai-responses', 'anthropic-messages'],
// The Maka arm records the wire its runtime actually dials: deepseek-v4-flash
// resolves to Responses, so a manifest claiming Chat here would describe a
// run that never happened — and the proxy parsing it that way measured none
// of it.
['openai-responses', 'openai-responses', 'anthropic-messages'],
);
assert.equal(manifest.maxConcurrentAttempts, 6);
assert.equal(
Expand Down
50 changes: 50 additions & 0 deletions packages/headless/src/__tests__/harness-ab-run.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -221,6 +221,56 @@ describe('runHarnessAbComparison', () => {
}
});

test('retries an infra-failed cell whose task id carries a dot', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-dotted-retry-'));
try {
const promptPath = join(dir, 'empty-system-prompt.txt');
await writeFile(promptPath, '', 'utf8');
let failingAttempts = 0;
const calls: string[] = [];
const failingArm = harnessArm('maka', calls);
failingArm.harborRunner = async () => {
failingAttempts += 1;
throw new Error('container failed after launch');
};
const input = {
runId: 'glm-harness-ab',
runRoot: dir,
resultsJsonlPath: join(dir, 'results.jsonl'),
systemPromptPath: promptPath,
resumeFingerprint: 'sha256:manifest',
evaluationTasks: [
{ id: 'install-windows-3.11', path: '/tasks/install-windows-3.11' },
{ id: 'plain', path: '/tasks/plain' },
],
arms: [failingArm, harnessArm('opencode', calls)] as const,
};

await runHarnessAbComparison(input);
assert.equal(failingAttempts, 2);

// The written round id normalizes the dot, so that is what an operator
// reads back out of results.jsonl and feeds to the retry.
await runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-install-windows-3-11'],
});
assert.equal(failingAttempts, 3);

// An operator recovering a sweep hands over a batch of ids. Naming only
// the first offender makes fixing a list of typos one round-trip each.
await assert.rejects(
runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-nope', 'ab-maka-r0-also-nope'],
}),
/unknown round ab-maka-r0-nope, ab-maka-r0-also-nope/,
);
} finally {
await rm(dir, { recursive: true, force: true });
}
});

test('continues the frozen schedule after a terminal cell infrastructure failure', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-resilient-schedule-'));
try {
Expand Down
9 changes: 3 additions & 6 deletions packages/headless/src/harbor-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,8 +49,10 @@ import {
type ProviderTokenUsage,
type ProviderUpstreamCredentialResolver,
} from './provider-auth-proxy.js';
export { modelIdForProvider } from './harness-agent-registry.js';
import {
harnessAgentImportPath,
modelIdForProvider,
providerProxyClientAuthMode,
providerProxyClientBaseUrl,
providerProxyUpstreamAuthMode,
Expand DownExpand Up@@ -1422,7 +1424,7 @@ async function hostSideProviderRuntime(options: HarborTaskRunnerOptions): Promis
: { apiKeyFile: apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
});
return {
env:
Expand DownExpand Up@@ -1909,11 +1911,6 @@ export function isBudgetExhaustedError(
* ("openai-compatible" routing "anthropic/claude-sonnet-4-5"). The cell's
* parseModelSpec preserves whatever it receives when a provider is set, so the
* stripping must happen here. */
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function modelForOpenCode(model: string, provider: string): string {
return model.includes('/') ? model : `${provider}/${model}`;
}
Expand Down
21 changes: 15 additions & 6 deletions packages/headless/src/harness-ab-run.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
import { buildRunManifestFingerprint } from './ab-manifest.js';
import { runArmCohort } from './ab-run.js';
import { buildAbRoundId, runArmCohort } from './ab-run.js';
import { withAbRunLock } from './ab-run-lock.js';
import type { AbComparisonSummary, ArmCohortResult } from './ab-types.js';
import { isEvaluatedOutcome, summarizeAbComparison } from './ab-summary.js';
Expand DownExpand Up@@ -142,13 +142,22 @@ async function executeHarnessArmCohort(input: RunHarnessArmCohortInput): Promise
if (retryRoundIds.size !== (input.retryAdjudicatedInfraRoundIdsOnce?.length ?? 0)) {
throw new Error('adjudicated infra retry round ids must be unique');
}
// Build the candidates with the same helper the cohort writes with. Spelling
// the id out here instead let the two drift: `buildAbRoundId` normalizes `.`
// to `-`, so a retry naming `install-windows-3.11` was rejected as unknown —
// and because the check throws rather than skips, one dotted task took the
// whole retry batch down with it.
const validRoundIds = new Set(
input.evaluationTasks.flatMap((task) => input.arms.map((arm) => `ab-${arm.id}-r0-${task.id}`)),
input.evaluationTasks.flatMap((task) =>
input.arms.map((arm) => buildAbRoundId(undefined, arm.id, 0, task.id)),
),
);
for (const roundId of retryRoundIds) {
if (!validRoundIds.has(roundId)) {
throw new Error(`adjudicated infra retry names unknown round ${roundId}`);
}
// Report every unknown id at once. An operator recovering a sweep hands over
// a batch of them, and failing on the first turns one typo into as many
// round-trips as there are mistakes.
const unknownRoundIds = [...retryRoundIds].filter((roundId) => !validRoundIds.has(roundId));
if (unknownRoundIds.length > 0) {
throw new Error(`adjudicated infra retry names unknown round ${unknownRoundIds.join(', ')}`);
}
const preexistingEventIds = new Set(
(await readFixedPromptWal(input.resultsJsonlPath))
Expand Down
64 changes: 63 additions & 1 deletion packages/headless/src/harness-agent-registry.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
import { PROVIDER_DEFAULTS, type ProviderType } from '@maka/core/llm-connections';
import { PROVIDER_DEFAULTS, type ModelInfo, type ProviderType } from '@maka/core/llm-connections';
import { type ModelRuntimeWire, resolveModelRuntime } from '@maka/runtime/model-runtime';
import type { ProviderAuthProxyMode, ProviderUsageProtocol } from './provider-auth-proxy.js';
import { modelApiProtocolFromEnv, selectedModelApiProtocol } from './provider-env.js';

export type HarnessAgentId =
| 'maka'
Expand DownExpand Up@@ -68,23 +70,83 @@ export function providerProxyUpstreamAuthMode(
: 'bearer';
}

/**
* The model id as the provider itself spells it, with the catalog's `provider/`
* prefix removed. This is what the runtime dials with, so it is also the only
* spelling any provider-facing decision may be made on.
*/
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function providerProxyUsageProtocol(
agent: HarnessAgentId,
provider: string,
apiProtocol?: string,
modelId?: string,
): ProviderUsageProtocol | undefined {
if (agent === 'codex') return 'openai-responses-sse';
if (agent === 'claude-code') return 'anthropic-sse';
if (agent === 'kimi-code') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'openai-chat') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'anthropic-messages')
return 'anthropic-sse';
// The Maka arm dials whatever wire its own runtime resolves, so that runtime
// is the authority here — the adapter kind is a guess, and a guess that
// drifts is not a gap but a wrong number: when deepseek-v4-flash moved to
// Responses, a proxy still parsing Chat SSE never saw `[DONE]`, recorded
// every request `interrupted` with no usage, and the runner threw each
// graded cell away as an infra failure.
//
// Which model is not optional information for the Maka arm: without it there
// is nothing to ask the runtime and the answer silently degrades back to the
// guess. Say so rather than returning a plausible wrong number. The id is
// normalized here so a caller passing the catalog spelling cannot resolve a
// different wire than the one the runtime dials — `resolveModelRuntime`
// does not recognize `deepseek/deepseek-v4-flash` and falls back to Chat.
if (agent === 'maka') {
if (!modelId) throw new Error('providerProxyUsageProtocol: the maka arm requires a model id');
const wire = makaRuntimeWire(provider, modelIdForProvider(modelId, provider), apiProtocol);
if (wire) return usageProtocolForWire(wire);
}
const definition = providerDefinition(provider);
if (definition?.runtimeAdapter.kind === 'anthropic') return 'anthropic-sse';
if (definition?.runtimeAdapter.kind === 'openai-compatible') return 'openai-chat-sse';
return undefined;
}

function makaRuntimeWire(
provider: string,
modelId: string,
apiProtocol?: string,
): ModelRuntimeWire | null {
if (!providerDefinition(provider)) return null;
// The connection the runtime will actually build, not one this side invents:
// an advertised protocol only reaches the model entry for the providers whose
// connections carry it, and `selectedModelApiProtocol` is where that is
// decided. Honouring it here where the runtime drops it would resolve a wire
// nothing dials — the wrong-number failure this whole path exists to remove.
const advertised = selectedModelApiProtocol(
provider as ProviderType,
modelApiProtocolFromEnv(apiProtocol),
);
return resolveModelRuntime(
{
providerType: provider as ProviderType,
...(advertised ? { models: [{ id: modelId, apiProtocol: advertised }] } : {}),
},
modelId,
).wire;
}

function usageProtocolForWire(wire: ModelRuntimeWire): ProviderUsageProtocol | undefined {
if (wire === 'anthropic-messages') return 'anthropic-sse';
if (wire === 'openai-chat') return 'openai-chat-sse';
if (wire === 'openai-responses') return 'openai-responses-sse';
return undefined;
}

function providerDefinition(provider: string) {
return (PROVIDER_DEFAULTS as Partial<Record<string, (typeof PROVIDER_DEFAULTS)[ProviderType]>>)[
provider
Expand Down
2 changes: 1 addition & 1 deletion packages/headless/src/pier-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -915,7 +915,7 @@ async function pierProviderRuntime(
: { apiKeyFile: options.apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
};
const proxy =
options.providerProxyHub && proxyPort !== undefined
Expand Down
27 changes: 24 additions & 3 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,28 @@ import {
} from '@maka/core';
import type { RunHarborCellEnv } from './headless-run-env.js';

/**
* The protocol a connection actually carries, given what was advertised.
*
* Only two providers let an advertised protocol pick the wire: GitHub Copilot,
* where the account discovers it, and the Kimi Coding Plan, which is sold as
* two protocols against one account. Everywhere else the model's own catalog
* entry decides, and an advertised value is dropped.
*
* Anything deciding what wire the Maka runtime will dial has to apply this same
* rule, or it decides about a connection the runtime will never build. The
* proxy resolves its SSE parser that way (`providerProxyUsageProtocol`), and
* honouring the override where the runtime drops it is the same wrong-wire
* failure — a proxy parsing Chat while the runtime dials Responses records
* every request interrupted with no usage.
*/
export function selectedModelApiProtocol(
provider: ProviderType,
advertised: ModelInfo['apiProtocol'],
): ModelInfo['apiProtocol'] {
return provider === 'github-copilot' || provider === 'kimi-coding-plan' ? advertised : undefined;
}

export interface ProviderCredentialEnv {
apiKeys: readonly string[];
apiKeyFile: string;
Expand DownExpand Up@@ -218,8 +240,7 @@ function connectionFromEnv(
if (provider === 'github-copilot' && !modelApiProtocol) {
throw new Error('GitHub Copilot requires an account-discovered model protocol');
}
const selectedApiProtocol =
provider === 'github-copilot' || provider === 'kimi-coding-plan' ? modelApiProtocol : undefined;
const selectedApiProtocol = selectedModelApiProtocol(provider, modelApiProtocol);
return {
slug: values.MAKA_LLM_CONNECTION_SLUG ?? provider,
name: defaults.label,
Expand All@@ -237,7 +258,7 @@ function connectionFromEnv(
};
}

function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
export function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
if (value === 'openai-chat' || value === 'openai-responses' || value === 'anthropic-messages')
return value;
return undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
"./tool-output-delta": "./dist/tool-output-delta.js",
"./stream-watchdog": "./dist/stream-watchdog.js",
"./model-factory": "./dist/model-factory.js",
"./model-runtime": "./dist/model-runtime.js",
"./context-budget": "./dist/context-budget.js",
"./active-full-compact": "./dist/active-full-compact.js",
"./semantic-compact": "./dist/semantic-compact.js",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions packages/headless/harbor/run-harness-ab.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -854,8 +854,8 @@ export function harnessMakaAgentEnv(benchmarkProfile, env = process.env) {
};
}

function harnessMeasuredTransport(agentId, provider) {
const protocol = providerProxyUsageProtocol(agentId, provider);
function harnessMeasuredTransport(agentId, provider, model) {
const protocol = providerProxyUsageProtocol(agentId, provider, undefined, model);
if (protocol === 'openai-chat-sse') return 'openai-chat';
if (protocol === 'openai-responses-sse') return 'openai-responses';
if (protocol === 'anthropic-sse') return 'anthropic-messages';
Expand DownExpand Up@@ -929,7 +929,7 @@ export function buildHarnessAbManifest({
config: {
adapter: harnessAgentImportPath('maka'),
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport('maka', execution.provider) }
? { transport: harnessMeasuredTransport('maka', execution.provider, execution.model) }
: {}),
// The runner hands every arm MAKA_SYSTEM_PROMPT, but only the Maka
// cell applies it; the native CLIs hash it into their execution
Expand DownExpand Up@@ -964,7 +964,13 @@ export function buildHarnessAbManifest({
adapter: harnessAgentImportPath(profile.id),
...profile.config,
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport(profile.id, execution.provider) }
? {
transport: harnessMeasuredTransport(
profile.id,
execution.provider,
execution.model,
),
}
: {}),
...(profile.id === 'codex' && runtimeProfile.provider === 'deepseek'
? { modelCatalogFingerprint: CODEX_DEEPSEEK_MODEL_CATALOG_FINGERPRINT }
Expand Down
44 changes: 44 additions & 0 deletions packages/headless/src/__tests__/harbor-task-runner.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -126,6 +126,50 @@ test('DeepSeek routes each CLI through its native wire protocol', () => {
assert.equal(harnessAgentImportPath('reasonix'), 'reasonix_agent:MakaReasonixAgent');
});

test('the Maka arm measures the wire its own runtime resolves, not the adapter kind', () => {
// deepseek-v4-flash routes through the Responses API (`openAiAdapterApiProtocol`),
// so a proxy parsing it as Chat SSE never sees `[DONE]`, marks every request
// `interrupted`, and the runner throws the whole graded cell away as infra.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-responses-sse',
);
// Same provider, a model that stays on Chat Completions.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v3.2'),
'openai-chat-sse',
);
// An advertised protocol wins only where the runtime's own connection carries
// one. For DeepSeek it does not: `connectionFromEnv` drops it, so the runtime
// dials Responses regardless and a proxy that honoured the override would be
// parsing a wire nobody is speaking — the same wrong number, reintroduced
// through this function's own input.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', 'openai-chat', 'deepseek-v4-flash'),
'openai-responses-sse',
);
// The two providers whose connections do carry an advertised protocol have
// their own explicit branches above, asserted separately.
// Competitors run their own CLI, so the Maka runtime says nothing about them.
assert.equal(
providerProxyUsageProtocol('reasonix', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-chat-sse',
);
// The catalog spelling resolves to the same wire as the one the runtime dials.
// `resolveModelRuntime` does not recognize the prefixed id, so a caller that
// forwarded it raw would silently get the Chat guess back — this fix's own
// API re-entering the bug it exists to close.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek/deepseek-v4-flash'),
'openai-responses-sse',
);
// And a caller with no model id at all gets an error, not the guess.
assert.throws(
() => providerProxyUsageProtocol('maka', 'deepseek'),
/the maka arm requires a model id/,
);
});

interface FakeOptions {
reward?: string;
cell?: HarborCellOutput | null;
Expand Down
6 changes: 5 additions & 1 deletion packages/headless/src/__tests__/harness-ab-cli.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -717,7 +717,11 @@ test('harness CLI freezes the synchronized DeepSeek three-way composition', asyn
manifest.arms.map(
(arm: { metadata?: { config?: { transport?: string } } }) => arm.metadata?.config?.transport,
),
['openai-chat', 'openai-responses', 'anthropic-messages'],
// The Maka arm records the wire its runtime actually dials: deepseek-v4-flash
// resolves to Responses, so a manifest claiming Chat here would describe a
// run that never happened — and the proxy parsing it that way measured none
// of it.
['openai-responses', 'openai-responses', 'anthropic-messages'],
);
assert.equal(manifest.maxConcurrentAttempts, 6);
assert.equal(
Expand Down
50 changes: 50 additions & 0 deletions packages/headless/src/__tests__/harness-ab-run.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -221,6 +221,56 @@ describe('runHarnessAbComparison', () => {
}
});

test('retries an infra-failed cell whose task id carries a dot', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-dotted-retry-'));
try {
const promptPath = join(dir, 'empty-system-prompt.txt');
await writeFile(promptPath, '', 'utf8');
let failingAttempts = 0;
const calls: string[] = [];
const failingArm = harnessArm('maka', calls);
failingArm.harborRunner = async () => {
failingAttempts += 1;
throw new Error('container failed after launch');
};
const input = {
runId: 'glm-harness-ab',
runRoot: dir,
resultsJsonlPath: join(dir, 'results.jsonl'),
systemPromptPath: promptPath,
resumeFingerprint: 'sha256:manifest',
evaluationTasks: [
{ id: 'install-windows-3.11', path: '/tasks/install-windows-3.11' },
{ id: 'plain', path: '/tasks/plain' },
],
arms: [failingArm, harnessArm('opencode', calls)] as const,
};

await runHarnessAbComparison(input);
assert.equal(failingAttempts, 2);

// The written round id normalizes the dot, so that is what an operator
// reads back out of results.jsonl and feeds to the retry.
await runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-install-windows-3-11'],
});
assert.equal(failingAttempts, 3);

// An operator recovering a sweep hands over a batch of ids. Naming only
// the first offender makes fixing a list of typos one round-trip each.
await assert.rejects(
runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-nope', 'ab-maka-r0-also-nope'],
}),
/unknown round ab-maka-r0-nope, ab-maka-r0-also-nope/,
);
} finally {
await rm(dir, { recursive: true, force: true });
}
});

test('continues the frozen schedule after a terminal cell infrastructure failure', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-resilient-schedule-'));
try {
Expand Down
9 changes: 3 additions & 6 deletions packages/headless/src/harbor-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,8 +49,10 @@ import {
type ProviderTokenUsage,
type ProviderUpstreamCredentialResolver,
} from './provider-auth-proxy.js';
export { modelIdForProvider } from './harness-agent-registry.js';
import {
harnessAgentImportPath,
modelIdForProvider,
providerProxyClientAuthMode,
providerProxyClientBaseUrl,
providerProxyUpstreamAuthMode,
Expand DownExpand Up@@ -1422,7 +1424,7 @@ async function hostSideProviderRuntime(options: HarborTaskRunnerOptions): Promis
: { apiKeyFile: apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
});
return {
env:
Expand DownExpand Up@@ -1909,11 +1911,6 @@ export function isBudgetExhaustedError(
* ("openai-compatible" routing "anthropic/claude-sonnet-4-5"). The cell's
* parseModelSpec preserves whatever it receives when a provider is set, so the
* stripping must happen here. */
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function modelForOpenCode(model: string, provider: string): string {
return model.includes('/') ? model : `${provider}/${model}`;
}
Expand Down
21 changes: 15 additions & 6 deletions packages/headless/src/harness-ab-run.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
import { buildRunManifestFingerprint } from './ab-manifest.js';
import { runArmCohort } from './ab-run.js';
import { buildAbRoundId, runArmCohort } from './ab-run.js';
import { withAbRunLock } from './ab-run-lock.js';
import type { AbComparisonSummary, ArmCohortResult } from './ab-types.js';
import { isEvaluatedOutcome, summarizeAbComparison } from './ab-summary.js';
Expand DownExpand Up@@ -142,13 +142,22 @@ async function executeHarnessArmCohort(input: RunHarnessArmCohortInput): Promise
if (retryRoundIds.size !== (input.retryAdjudicatedInfraRoundIdsOnce?.length ?? 0)) {
throw new Error('adjudicated infra retry round ids must be unique');
}
// Build the candidates with the same helper the cohort writes with. Spelling
// the id out here instead let the two drift: `buildAbRoundId` normalizes `.`
// to `-`, so a retry naming `install-windows-3.11` was rejected as unknown —
// and because the check throws rather than skips, one dotted task took the
// whole retry batch down with it.
const validRoundIds = new Set(
input.evaluationTasks.flatMap((task) => input.arms.map((arm) => `ab-${arm.id}-r0-${task.id}`)),
input.evaluationTasks.flatMap((task) =>
input.arms.map((arm) => buildAbRoundId(undefined, arm.id, 0, task.id)),
),
);
for (const roundId of retryRoundIds) {
if (!validRoundIds.has(roundId)) {
throw new Error(`adjudicated infra retry names unknown round ${roundId}`);
}
// Report every unknown id at once. An operator recovering a sweep hands over
// a batch of them, and failing on the first turns one typo into as many
// round-trips as there are mistakes.
const unknownRoundIds = [...retryRoundIds].filter((roundId) => !validRoundIds.has(roundId));
if (unknownRoundIds.length > 0) {
throw new Error(`adjudicated infra retry names unknown round ${unknownRoundIds.join(', ')}`);
}
const preexistingEventIds = new Set(
(await readFixedPromptWal(input.resultsJsonlPath))
Expand Down
64 changes: 63 additions & 1 deletion packages/headless/src/harness-agent-registry.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
import { PROVIDER_DEFAULTS, type ProviderType } from '@maka/core/llm-connections';
import { PROVIDER_DEFAULTS, type ModelInfo, type ProviderType } from '@maka/core/llm-connections';
import { type ModelRuntimeWire, resolveModelRuntime } from '@maka/runtime/model-runtime';
import type { ProviderAuthProxyMode, ProviderUsageProtocol } from './provider-auth-proxy.js';
import { modelApiProtocolFromEnv, selectedModelApiProtocol } from './provider-env.js';

export type HarnessAgentId =
| 'maka'
Expand DownExpand Up@@ -68,23 +70,83 @@ export function providerProxyUpstreamAuthMode(
: 'bearer';
}

/**
* The model id as the provider itself spells it, with the catalog's `provider/`
* prefix removed. This is what the runtime dials with, so it is also the only
* spelling any provider-facing decision may be made on.
*/
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function providerProxyUsageProtocol(
agent: HarnessAgentId,
provider: string,
apiProtocol?: string,
modelId?: string,
): ProviderUsageProtocol | undefined {
if (agent === 'codex') return 'openai-responses-sse';
if (agent === 'claude-code') return 'anthropic-sse';
if (agent === 'kimi-code') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'openai-chat') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'anthropic-messages')
return 'anthropic-sse';
// The Maka arm dials whatever wire its own runtime resolves, so that runtime
// is the authority here — the adapter kind is a guess, and a guess that
// drifts is not a gap but a wrong number: when deepseek-v4-flash moved to
// Responses, a proxy still parsing Chat SSE never saw `[DONE]`, recorded
// every request `interrupted` with no usage, and the runner threw each
// graded cell away as an infra failure.
//
// Which model is not optional information for the Maka arm: without it there
// is nothing to ask the runtime and the answer silently degrades back to the
// guess. Say so rather than returning a plausible wrong number. The id is
// normalized here so a caller passing the catalog spelling cannot resolve a
// different wire than the one the runtime dials — `resolveModelRuntime`
// does not recognize `deepseek/deepseek-v4-flash` and falls back to Chat.
if (agent === 'maka') {
if (!modelId) throw new Error('providerProxyUsageProtocol: the maka arm requires a model id');
const wire = makaRuntimeWire(provider, modelIdForProvider(modelId, provider), apiProtocol);
if (wire) return usageProtocolForWire(wire);
}
const definition = providerDefinition(provider);
if (definition?.runtimeAdapter.kind === 'anthropic') return 'anthropic-sse';
if (definition?.runtimeAdapter.kind === 'openai-compatible') return 'openai-chat-sse';
return undefined;
}

function makaRuntimeWire(
provider: string,
modelId: string,
apiProtocol?: string,
): ModelRuntimeWire | null {
if (!providerDefinition(provider)) return null;
// The connection the runtime will actually build, not one this side invents:
// an advertised protocol only reaches the model entry for the providers whose
// connections carry it, and `selectedModelApiProtocol` is where that is
// decided. Honouring it here where the runtime drops it would resolve a wire
// nothing dials — the wrong-number failure this whole path exists to remove.
const advertised = selectedModelApiProtocol(
provider as ProviderType,
modelApiProtocolFromEnv(apiProtocol),
);
return resolveModelRuntime(
{
providerType: provider as ProviderType,
...(advertised ? { models: [{ id: modelId, apiProtocol: advertised }] } : {}),
},
modelId,
).wire;
}

function usageProtocolForWire(wire: ModelRuntimeWire): ProviderUsageProtocol | undefined {
if (wire === 'anthropic-messages') return 'anthropic-sse';
if (wire === 'openai-chat') return 'openai-chat-sse';
if (wire === 'openai-responses') return 'openai-responses-sse';
return undefined;
}

function providerDefinition(provider: string) {
return (PROVIDER_DEFAULTS as Partial<Record<string, (typeof PROVIDER_DEFAULTS)[ProviderType]>>)[
provider
Expand Down
2 changes: 1 addition & 1 deletion packages/headless/src/pier-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -915,7 +915,7 @@ async function pierProviderRuntime(
: { apiKeyFile: options.apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
};
const proxy =
options.providerProxyHub && proxyPort !== undefined
Expand Down
27 changes: 24 additions & 3 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,28 @@ import {
} from '@maka/core';
import type { RunHarborCellEnv } from './headless-run-env.js';

/**
* The protocol a connection actually carries, given what was advertised.
*
* Only two providers let an advertised protocol pick the wire: GitHub Copilot,
* where the account discovers it, and the Kimi Coding Plan, which is sold as
* two protocols against one account. Everywhere else the model's own catalog
* entry decides, and an advertised value is dropped.
*
* Anything deciding what wire the Maka runtime will dial has to apply this same
* rule, or it decides about a connection the runtime will never build. The
* proxy resolves its SSE parser that way (`providerProxyUsageProtocol`), and
* honouring the override where the runtime drops it is the same wrong-wire
* failure — a proxy parsing Chat while the runtime dials Responses records
* every request interrupted with no usage.
*/
export function selectedModelApiProtocol(
provider: ProviderType,
advertised: ModelInfo['apiProtocol'],
): ModelInfo['apiProtocol'] {
return provider === 'github-copilot' || provider === 'kimi-coding-plan' ? advertised : undefined;
}

export interface ProviderCredentialEnv {
apiKeys: readonly string[];
apiKeyFile: string;
Expand DownExpand Up@@ -218,8 +240,7 @@ function connectionFromEnv(
if (provider === 'github-copilot' && !modelApiProtocol) {
throw new Error('GitHub Copilot requires an account-discovered model protocol');
}
const selectedApiProtocol =
provider === 'github-copilot' || provider === 'kimi-coding-plan' ? modelApiProtocol : undefined;
const selectedApiProtocol = selectedModelApiProtocol(provider, modelApiProtocol);
return {
slug: values.MAKA_LLM_CONNECTION_SLUG ?? provider,
name: defaults.label,
Expand All@@ -237,7 +258,7 @@ function connectionFromEnv(
};
}

function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
export function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
if (value === 'openai-chat' || value === 'openai-responses' || value === 'anthropic-messages')
return value;
return undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
"./tool-output-delta": "./dist/tool-output-delta.js",
"./stream-watchdog": "./dist/stream-watchdog.js",
"./model-factory": "./dist/model-factory.js",
"./model-runtime": "./dist/model-runtime.js",
"./context-budget": "./dist/context-budget.js",
"./active-full-compact": "./dist/active-full-compact.js",
"./semantic-compact": "./dist/semantic-compact.js",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions packages/headless/harbor/run-harness-ab.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -854,8 +854,8 @@ export function harnessMakaAgentEnv(benchmarkProfile, env = process.env) {
};
}

function harnessMeasuredTransport(agentId, provider) {
const protocol = providerProxyUsageProtocol(agentId, provider);
function harnessMeasuredTransport(agentId, provider, model) {
const protocol = providerProxyUsageProtocol(agentId, provider, undefined, model);
if (protocol === 'openai-chat-sse') return 'openai-chat';
if (protocol === 'openai-responses-sse') return 'openai-responses';
if (protocol === 'anthropic-sse') return 'anthropic-messages';
Expand DownExpand Up@@ -929,7 +929,7 @@ export function buildHarnessAbManifest({
config: {
adapter: harnessAgentImportPath('maka'),
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport('maka', execution.provider) }
? { transport: harnessMeasuredTransport('maka', execution.provider, execution.model) }
: {}),
// The runner hands every arm MAKA_SYSTEM_PROMPT, but only the Maka
// cell applies it; the native CLIs hash it into their execution
Expand DownExpand Up@@ -964,7 +964,13 @@ export function buildHarnessAbManifest({
adapter: harnessAgentImportPath(profile.id),
...profile.config,
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport(profile.id, execution.provider) }
? {
transport: harnessMeasuredTransport(
profile.id,
execution.provider,
execution.model,
),
}
: {}),
...(profile.id === 'codex' && runtimeProfile.provider === 'deepseek'
? { modelCatalogFingerprint: CODEX_DEEPSEEK_MODEL_CATALOG_FINGERPRINT }
Expand Down
44 changes: 44 additions & 0 deletions packages/headless/src/__tests__/harbor-task-runner.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -126,6 +126,50 @@ test('DeepSeek routes each CLI through its native wire protocol', () => {
assert.equal(harnessAgentImportPath('reasonix'), 'reasonix_agent:MakaReasonixAgent');
});

test('the Maka arm measures the wire its own runtime resolves, not the adapter kind', () => {
// deepseek-v4-flash routes through the Responses API (`openAiAdapterApiProtocol`),
// so a proxy parsing it as Chat SSE never sees `[DONE]`, marks every request
// `interrupted`, and the runner throws the whole graded cell away as infra.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-responses-sse',
);
// Same provider, a model that stays on Chat Completions.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v3.2'),
'openai-chat-sse',
);
// An advertised protocol wins only where the runtime's own connection carries
// one. For DeepSeek it does not: `connectionFromEnv` drops it, so the runtime
// dials Responses regardless and a proxy that honoured the override would be
// parsing a wire nobody is speaking — the same wrong number, reintroduced
// through this function's own input.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', 'openai-chat', 'deepseek-v4-flash'),
'openai-responses-sse',
);
// The two providers whose connections do carry an advertised protocol have
// their own explicit branches above, asserted separately.
// Competitors run their own CLI, so the Maka runtime says nothing about them.
assert.equal(
providerProxyUsageProtocol('reasonix', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-chat-sse',
);
// The catalog spelling resolves to the same wire as the one the runtime dials.
// `resolveModelRuntime` does not recognize the prefixed id, so a caller that
// forwarded it raw would silently get the Chat guess back — this fix's own
// API re-entering the bug it exists to close.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek/deepseek-v4-flash'),
'openai-responses-sse',
);
// And a caller with no model id at all gets an error, not the guess.
assert.throws(
() => providerProxyUsageProtocol('maka', 'deepseek'),
/the maka arm requires a model id/,
);
});

interface FakeOptions {
reward?: string;
cell?: HarborCellOutput | null;
Expand Down
6 changes: 5 additions & 1 deletion packages/headless/src/__tests__/harness-ab-cli.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -717,7 +717,11 @@ test('harness CLI freezes the synchronized DeepSeek three-way composition', asyn
manifest.arms.map(
(arm: { metadata?: { config?: { transport?: string } } }) => arm.metadata?.config?.transport,
),
['openai-chat', 'openai-responses', 'anthropic-messages'],
// The Maka arm records the wire its runtime actually dials: deepseek-v4-flash
// resolves to Responses, so a manifest claiming Chat here would describe a
// run that never happened — and the proxy parsing it that way measured none
// of it.
['openai-responses', 'openai-responses', 'anthropic-messages'],
);
assert.equal(manifest.maxConcurrentAttempts, 6);
assert.equal(
Expand Down
50 changes: 50 additions & 0 deletions packages/headless/src/__tests__/harness-ab-run.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -221,6 +221,56 @@ describe('runHarnessAbComparison', () => {
}
});

test('retries an infra-failed cell whose task id carries a dot', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-dotted-retry-'));
try {
const promptPath = join(dir, 'empty-system-prompt.txt');
await writeFile(promptPath, '', 'utf8');
let failingAttempts = 0;
const calls: string[] = [];
const failingArm = harnessArm('maka', calls);
failingArm.harborRunner = async () => {
failingAttempts += 1;
throw new Error('container failed after launch');
};
const input = {
runId: 'glm-harness-ab',
runRoot: dir,
resultsJsonlPath: join(dir, 'results.jsonl'),
systemPromptPath: promptPath,
resumeFingerprint: 'sha256:manifest',
evaluationTasks: [
{ id: 'install-windows-3.11', path: '/tasks/install-windows-3.11' },
{ id: 'plain', path: '/tasks/plain' },
],
arms: [failingArm, harnessArm('opencode', calls)] as const,
};

await runHarnessAbComparison(input);
assert.equal(failingAttempts, 2);

// The written round id normalizes the dot, so that is what an operator
// reads back out of results.jsonl and feeds to the retry.
await runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-install-windows-3-11'],
});
assert.equal(failingAttempts, 3);

// An operator recovering a sweep hands over a batch of ids. Naming only
// the first offender makes fixing a list of typos one round-trip each.
await assert.rejects(
runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-nope', 'ab-maka-r0-also-nope'],
}),
/unknown round ab-maka-r0-nope, ab-maka-r0-also-nope/,
);
} finally {
await rm(dir, { recursive: true, force: true });
}
});

test('continues the frozen schedule after a terminal cell infrastructure failure', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-resilient-schedule-'));
try {
Expand Down
9 changes: 3 additions & 6 deletions packages/headless/src/harbor-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,8 +49,10 @@ import {
type ProviderTokenUsage,
type ProviderUpstreamCredentialResolver,
} from './provider-auth-proxy.js';
export { modelIdForProvider } from './harness-agent-registry.js';
import {
harnessAgentImportPath,
modelIdForProvider,
providerProxyClientAuthMode,
providerProxyClientBaseUrl,
providerProxyUpstreamAuthMode,
Expand DownExpand Up@@ -1422,7 +1424,7 @@ async function hostSideProviderRuntime(options: HarborTaskRunnerOptions): Promis
: { apiKeyFile: apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
});
return {
env:
Expand DownExpand Up@@ -1909,11 +1911,6 @@ export function isBudgetExhaustedError(
* ("openai-compatible" routing "anthropic/claude-sonnet-4-5"). The cell's
* parseModelSpec preserves whatever it receives when a provider is set, so the
* stripping must happen here. */
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function modelForOpenCode(model: string, provider: string): string {
return model.includes('/') ? model : `${provider}/${model}`;
}
Expand Down
21 changes: 15 additions & 6 deletions packages/headless/src/harness-ab-run.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
import { buildRunManifestFingerprint } from './ab-manifest.js';
import { runArmCohort } from './ab-run.js';
import { buildAbRoundId, runArmCohort } from './ab-run.js';
import { withAbRunLock } from './ab-run-lock.js';
import type { AbComparisonSummary, ArmCohortResult } from './ab-types.js';
import { isEvaluatedOutcome, summarizeAbComparison } from './ab-summary.js';
Expand DownExpand Up@@ -142,13 +142,22 @@ async function executeHarnessArmCohort(input: RunHarnessArmCohortInput): Promise
if (retryRoundIds.size !== (input.retryAdjudicatedInfraRoundIdsOnce?.length ?? 0)) {
throw new Error('adjudicated infra retry round ids must be unique');
}
// Build the candidates with the same helper the cohort writes with. Spelling
// the id out here instead let the two drift: `buildAbRoundId` normalizes `.`
// to `-`, so a retry naming `install-windows-3.11` was rejected as unknown —
// and because the check throws rather than skips, one dotted task took the
// whole retry batch down with it.
const validRoundIds = new Set(
input.evaluationTasks.flatMap((task) => input.arms.map((arm) => `ab-${arm.id}-r0-${task.id}`)),
input.evaluationTasks.flatMap((task) =>
input.arms.map((arm) => buildAbRoundId(undefined, arm.id, 0, task.id)),
),
);
for (const roundId of retryRoundIds) {
if (!validRoundIds.has(roundId)) {
throw new Error(`adjudicated infra retry names unknown round ${roundId}`);
}
// Report every unknown id at once. An operator recovering a sweep hands over
// a batch of them, and failing on the first turns one typo into as many
// round-trips as there are mistakes.
const unknownRoundIds = [...retryRoundIds].filter((roundId) => !validRoundIds.has(roundId));
if (unknownRoundIds.length > 0) {
throw new Error(`adjudicated infra retry names unknown round ${unknownRoundIds.join(', ')}`);
}
const preexistingEventIds = new Set(
(await readFixedPromptWal(input.resultsJsonlPath))
Expand Down
64 changes: 63 additions & 1 deletion packages/headless/src/harness-agent-registry.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
import { PROVIDER_DEFAULTS, type ProviderType } from '@maka/core/llm-connections';
import { PROVIDER_DEFAULTS, type ModelInfo, type ProviderType } from '@maka/core/llm-connections';
import { type ModelRuntimeWire, resolveModelRuntime } from '@maka/runtime/model-runtime';
import type { ProviderAuthProxyMode, ProviderUsageProtocol } from './provider-auth-proxy.js';
import { modelApiProtocolFromEnv, selectedModelApiProtocol } from './provider-env.js';

export type HarnessAgentId =
| 'maka'
Expand DownExpand Up@@ -68,23 +70,83 @@ export function providerProxyUpstreamAuthMode(
: 'bearer';
}

/**
* The model id as the provider itself spells it, with the catalog's `provider/`
* prefix removed. This is what the runtime dials with, so it is also the only
* spelling any provider-facing decision may be made on.
*/
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function providerProxyUsageProtocol(
agent: HarnessAgentId,
provider: string,
apiProtocol?: string,
modelId?: string,
): ProviderUsageProtocol | undefined {
if (agent === 'codex') return 'openai-responses-sse';
if (agent === 'claude-code') return 'anthropic-sse';
if (agent === 'kimi-code') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'openai-chat') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'anthropic-messages')
return 'anthropic-sse';
// The Maka arm dials whatever wire its own runtime resolves, so that runtime
// is the authority here — the adapter kind is a guess, and a guess that
// drifts is not a gap but a wrong number: when deepseek-v4-flash moved to
// Responses, a proxy still parsing Chat SSE never saw `[DONE]`, recorded
// every request `interrupted` with no usage, and the runner threw each
// graded cell away as an infra failure.
//
// Which model is not optional information for the Maka arm: without it there
// is nothing to ask the runtime and the answer silently degrades back to the
// guess. Say so rather than returning a plausible wrong number. The id is
// normalized here so a caller passing the catalog spelling cannot resolve a
// different wire than the one the runtime dials — `resolveModelRuntime`
// does not recognize `deepseek/deepseek-v4-flash` and falls back to Chat.
if (agent === 'maka') {
if (!modelId) throw new Error('providerProxyUsageProtocol: the maka arm requires a model id');
const wire = makaRuntimeWire(provider, modelIdForProvider(modelId, provider), apiProtocol);
if (wire) return usageProtocolForWire(wire);
}
const definition = providerDefinition(provider);
if (definition?.runtimeAdapter.kind === 'anthropic') return 'anthropic-sse';
if (definition?.runtimeAdapter.kind === 'openai-compatible') return 'openai-chat-sse';
return undefined;
}

function makaRuntimeWire(
provider: string,
modelId: string,
apiProtocol?: string,
): ModelRuntimeWire | null {
if (!providerDefinition(provider)) return null;
// The connection the runtime will actually build, not one this side invents:
// an advertised protocol only reaches the model entry for the providers whose
// connections carry it, and `selectedModelApiProtocol` is where that is
// decided. Honouring it here where the runtime drops it would resolve a wire
// nothing dials — the wrong-number failure this whole path exists to remove.
const advertised = selectedModelApiProtocol(
provider as ProviderType,
modelApiProtocolFromEnv(apiProtocol),
);
return resolveModelRuntime(
{
providerType: provider as ProviderType,
...(advertised ? { models: [{ id: modelId, apiProtocol: advertised }] } : {}),
},
modelId,
).wire;
}

function usageProtocolForWire(wire: ModelRuntimeWire): ProviderUsageProtocol | undefined {
if (wire === 'anthropic-messages') return 'anthropic-sse';
if (wire === 'openai-chat') return 'openai-chat-sse';
if (wire === 'openai-responses') return 'openai-responses-sse';
return undefined;
}

function providerDefinition(provider: string) {
return (PROVIDER_DEFAULTS as Partial<Record<string, (typeof PROVIDER_DEFAULTS)[ProviderType]>>)[
provider
Expand Down
2 changes: 1 addition & 1 deletion packages/headless/src/pier-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -915,7 +915,7 @@ async function pierProviderRuntime(
: { apiKeyFile: options.apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
};
const proxy =
options.providerProxyHub && proxyPort !== undefined
Expand Down
27 changes: 24 additions & 3 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,28 @@ import {
} from '@maka/core';
import type { RunHarborCellEnv } from './headless-run-env.js';

/**
* The protocol a connection actually carries, given what was advertised.
*
* Only two providers let an advertised protocol pick the wire: GitHub Copilot,
* where the account discovers it, and the Kimi Coding Plan, which is sold as
* two protocols against one account. Everywhere else the model's own catalog
* entry decides, and an advertised value is dropped.
*
* Anything deciding what wire the Maka runtime will dial has to apply this same
* rule, or it decides about a connection the runtime will never build. The
* proxy resolves its SSE parser that way (`providerProxyUsageProtocol`), and
* honouring the override where the runtime drops it is the same wrong-wire
* failure — a proxy parsing Chat while the runtime dials Responses records
* every request interrupted with no usage.
*/
export function selectedModelApiProtocol(
provider: ProviderType,
advertised: ModelInfo['apiProtocol'],
): ModelInfo['apiProtocol'] {
return provider === 'github-copilot' || provider === 'kimi-coding-plan' ? advertised : undefined;
}

export interface ProviderCredentialEnv {
apiKeys: readonly string[];
apiKeyFile: string;
Expand DownExpand Up@@ -218,8 +240,7 @@ function connectionFromEnv(
if (provider === 'github-copilot' && !modelApiProtocol) {
throw new Error('GitHub Copilot requires an account-discovered model protocol');
}
const selectedApiProtocol =
provider === 'github-copilot' || provider === 'kimi-coding-plan' ? modelApiProtocol : undefined;
const selectedApiProtocol = selectedModelApiProtocol(provider, modelApiProtocol);
return {
slug: values.MAKA_LLM_CONNECTION_SLUG ?? provider,
name: defaults.label,
Expand All@@ -237,7 +258,7 @@ function connectionFromEnv(
};
}

function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
export function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
if (value === 'openai-chat' || value === 'openai-responses' || value === 'anthropic-messages')
return value;
return undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
"./tool-output-delta": "./dist/tool-output-delta.js",
"./stream-watchdog": "./dist/stream-watchdog.js",
"./model-factory": "./dist/model-factory.js",
"./model-runtime": "./dist/model-runtime.js",
"./context-budget": "./dist/context-budget.js",
"./active-full-compact": "./dist/active-full-compact.js",
"./semantic-compact": "./dist/semantic-compact.js",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions packages/headless/harbor/run-harness-ab.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -854,8 +854,8 @@ export function harnessMakaAgentEnv(benchmarkProfile, env = process.env) {
};
}

function harnessMeasuredTransport(agentId, provider) {
const protocol = providerProxyUsageProtocol(agentId, provider);
function harnessMeasuredTransport(agentId, provider, model) {
const protocol = providerProxyUsageProtocol(agentId, provider, undefined, model);
if (protocol === 'openai-chat-sse') return 'openai-chat';
if (protocol === 'openai-responses-sse') return 'openai-responses';
if (protocol === 'anthropic-sse') return 'anthropic-messages';
Expand DownExpand Up@@ -929,7 +929,7 @@ export function buildHarnessAbManifest({
config: {
adapter: harnessAgentImportPath('maka'),
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport('maka', execution.provider) }
? { transport: harnessMeasuredTransport('maka', execution.provider, execution.model) }
: {}),
// The runner hands every arm MAKA_SYSTEM_PROMPT, but only the Maka
// cell applies it; the native CLIs hash it into their execution
Expand DownExpand Up@@ -964,7 +964,13 @@ export function buildHarnessAbManifest({
adapter: harnessAgentImportPath(profile.id),
...profile.config,
...(competitorProfiles.length > 1
? { transport: harnessMeasuredTransport(profile.id, execution.provider) }
? {
transport: harnessMeasuredTransport(
profile.id,
execution.provider,
execution.model,
),
}
: {}),
...(profile.id === 'codex' && runtimeProfile.provider === 'deepseek'
? { modelCatalogFingerprint: CODEX_DEEPSEEK_MODEL_CATALOG_FINGERPRINT }
Expand Down
44 changes: 44 additions & 0 deletions packages/headless/src/__tests__/harbor-task-runner.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -126,6 +126,50 @@ test('DeepSeek routes each CLI through its native wire protocol', () => {
assert.equal(harnessAgentImportPath('reasonix'), 'reasonix_agent:MakaReasonixAgent');
});

test('the Maka arm measures the wire its own runtime resolves, not the adapter kind', () => {
// deepseek-v4-flash routes through the Responses API (`openAiAdapterApiProtocol`),
// so a proxy parsing it as Chat SSE never sees `[DONE]`, marks every request
// `interrupted`, and the runner throws the whole graded cell away as infra.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-responses-sse',
);
// Same provider, a model that stays on Chat Completions.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek-v3.2'),
'openai-chat-sse',
);
// An advertised protocol wins only where the runtime's own connection carries
// one. For DeepSeek it does not: `connectionFromEnv` drops it, so the runtime
// dials Responses regardless and a proxy that honoured the override would be
// parsing a wire nobody is speaking — the same wrong number, reintroduced
// through this function's own input.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', 'openai-chat', 'deepseek-v4-flash'),
'openai-responses-sse',
);
// The two providers whose connections do carry an advertised protocol have
// their own explicit branches above, asserted separately.
// Competitors run their own CLI, so the Maka runtime says nothing about them.
assert.equal(
providerProxyUsageProtocol('reasonix', 'deepseek', undefined, 'deepseek-v4-flash'),
'openai-chat-sse',
);
// The catalog spelling resolves to the same wire as the one the runtime dials.
// `resolveModelRuntime` does not recognize the prefixed id, so a caller that
// forwarded it raw would silently get the Chat guess back — this fix's own
// API re-entering the bug it exists to close.
assert.equal(
providerProxyUsageProtocol('maka', 'deepseek', undefined, 'deepseek/deepseek-v4-flash'),
'openai-responses-sse',
);
// And a caller with no model id at all gets an error, not the guess.
assert.throws(
() => providerProxyUsageProtocol('maka', 'deepseek'),
/the maka arm requires a model id/,
);
});

interface FakeOptions {
reward?: string;
cell?: HarborCellOutput | null;
Expand Down
6 changes: 5 additions & 1 deletion packages/headless/src/__tests__/harness-ab-cli.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -717,7 +717,11 @@ test('harness CLI freezes the synchronized DeepSeek three-way composition', asyn
manifest.arms.map(
(arm: { metadata?: { config?: { transport?: string } } }) => arm.metadata?.config?.transport,
),
['openai-chat', 'openai-responses', 'anthropic-messages'],
// The Maka arm records the wire its runtime actually dials: deepseek-v4-flash
// resolves to Responses, so a manifest claiming Chat here would describe a
// run that never happened — and the proxy parsing it that way measured none
// of it.
['openai-responses', 'openai-responses', 'anthropic-messages'],
);
assert.equal(manifest.maxConcurrentAttempts, 6);
assert.equal(
Expand Down
50 changes: 50 additions & 0 deletions packages/headless/src/__tests__/harness-ab-run.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -221,6 +221,56 @@ describe('runHarnessAbComparison', () => {
}
});

test('retries an infra-failed cell whose task id carries a dot', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-dotted-retry-'));
try {
const promptPath = join(dir, 'empty-system-prompt.txt');
await writeFile(promptPath, '', 'utf8');
let failingAttempts = 0;
const calls: string[] = [];
const failingArm = harnessArm('maka', calls);
failingArm.harborRunner = async () => {
failingAttempts += 1;
throw new Error('container failed after launch');
};
const input = {
runId: 'glm-harness-ab',
runRoot: dir,
resultsJsonlPath: join(dir, 'results.jsonl'),
systemPromptPath: promptPath,
resumeFingerprint: 'sha256:manifest',
evaluationTasks: [
{ id: 'install-windows-3.11', path: '/tasks/install-windows-3.11' },
{ id: 'plain', path: '/tasks/plain' },
],
arms: [failingArm, harnessArm('opencode', calls)] as const,
};

await runHarnessAbComparison(input);
assert.equal(failingAttempts, 2);

// The written round id normalizes the dot, so that is what an operator
// reads back out of results.jsonl and feeds to the retry.
await runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-install-windows-3-11'],
});
assert.equal(failingAttempts, 3);

// An operator recovering a sweep hands over a batch of ids. Naming only
// the first offender makes fixing a list of typos one round-trip each.
await assert.rejects(
runHarnessAbComparison({
...input,
retryAdjudicatedInfraRoundIdsOnce: ['ab-maka-r0-nope', 'ab-maka-r0-also-nope'],
}),
/unknown round ab-maka-r0-nope, ab-maka-r0-also-nope/,
);
} finally {
await rm(dir, { recursive: true, force: true });
}
});

test('continues the frozen schedule after a terminal cell infrastructure failure', async () => {
const dir = await mkdtemp(join(tmpdir(), 'maka-harness-ab-resilient-schedule-'));
try {
Expand Down
9 changes: 3 additions & 6 deletions packages/headless/src/harbor-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,8 +49,10 @@ import {
type ProviderTokenUsage,
type ProviderUpstreamCredentialResolver,
} from './provider-auth-proxy.js';
export { modelIdForProvider } from './harness-agent-registry.js';
import {
harnessAgentImportPath,
modelIdForProvider,
providerProxyClientAuthMode,
providerProxyClientBaseUrl,
providerProxyUpstreamAuthMode,
Expand DownExpand Up@@ -1422,7 +1424,7 @@ async function hostSideProviderRuntime(options: HarborTaskRunnerOptions): Promis
: { apiKeyFile: apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
});
return {
env:
Expand DownExpand Up@@ -1909,11 +1911,6 @@ export function isBudgetExhaustedError(
* ("openai-compatible" routing "anthropic/claude-sonnet-4-5"). The cell's
* parseModelSpec preserves whatever it receives when a provider is set, so the
* stripping must happen here. */
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function modelForOpenCode(model: string, provider: string): string {
return model.includes('/') ? model : `${provider}/${model}`;
}
Expand Down
21 changes: 15 additions & 6 deletions packages/headless/src/harness-ab-run.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
import { buildRunManifestFingerprint } from './ab-manifest.js';
import { runArmCohort } from './ab-run.js';
import { buildAbRoundId, runArmCohort } from './ab-run.js';
import { withAbRunLock } from './ab-run-lock.js';
import type { AbComparisonSummary, ArmCohortResult } from './ab-types.js';
import { isEvaluatedOutcome, summarizeAbComparison } from './ab-summary.js';
Expand DownExpand Up@@ -142,13 +142,22 @@ async function executeHarnessArmCohort(input: RunHarnessArmCohortInput): Promise
if (retryRoundIds.size !== (input.retryAdjudicatedInfraRoundIdsOnce?.length ?? 0)) {
throw new Error('adjudicated infra retry round ids must be unique');
}
// Build the candidates with the same helper the cohort writes with. Spelling
// the id out here instead let the two drift: `buildAbRoundId` normalizes `.`
// to `-`, so a retry naming `install-windows-3.11` was rejected as unknown —
// and because the check throws rather than skips, one dotted task took the
// whole retry batch down with it.
const validRoundIds = new Set(
input.evaluationTasks.flatMap((task) => input.arms.map((arm) => `ab-${arm.id}-r0-${task.id}`)),
input.evaluationTasks.flatMap((task) =>
input.arms.map((arm) => buildAbRoundId(undefined, arm.id, 0, task.id)),
),
);
for (const roundId of retryRoundIds) {
if (!validRoundIds.has(roundId)) {
throw new Error(`adjudicated infra retry names unknown round ${roundId}`);
}
// Report every unknown id at once. An operator recovering a sweep hands over
// a batch of them, and failing on the first turns one typo into as many
// round-trips as there are mistakes.
const unknownRoundIds = [...retryRoundIds].filter((roundId) => !validRoundIds.has(roundId));
if (unknownRoundIds.length > 0) {
throw new Error(`adjudicated infra retry names unknown round ${unknownRoundIds.join(', ')}`);
}
const preexistingEventIds = new Set(
(await readFixedPromptWal(input.resultsJsonlPath))
Expand Down
64 changes: 63 additions & 1 deletion packages/headless/src/harness-agent-registry.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
import { PROVIDER_DEFAULTS, type ProviderType } from '@maka/core/llm-connections';
import { PROVIDER_DEFAULTS, type ModelInfo, type ProviderType } from '@maka/core/llm-connections';
import { type ModelRuntimeWire, resolveModelRuntime } from '@maka/runtime/model-runtime';
import type { ProviderAuthProxyMode, ProviderUsageProtocol } from './provider-auth-proxy.js';
import { modelApiProtocolFromEnv, selectedModelApiProtocol } from './provider-env.js';

export type HarnessAgentId =
| 'maka'
Expand DownExpand Up@@ -68,23 +70,83 @@ export function providerProxyUpstreamAuthMode(
: 'bearer';
}

/**
* The model id as the provider itself spells it, with the catalog's `provider/`
* prefix removed. This is what the runtime dials with, so it is also the only
* spelling any provider-facing decision may be made on.
*/
export function modelIdForProvider(model: string, provider: string): string {
const prefix = `${provider}/`;
return model.startsWith(prefix) ? model.slice(prefix.length) : model;
}

export function providerProxyUsageProtocol(
agent: HarnessAgentId,
provider: string,
apiProtocol?: string,
modelId?: string,
): ProviderUsageProtocol | undefined {
if (agent === 'codex') return 'openai-responses-sse';
if (agent === 'claude-code') return 'anthropic-sse';
if (agent === 'kimi-code') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'openai-chat') return 'openai-chat-sse';
if (provider === 'kimi-coding-plan' && apiProtocol === 'anthropic-messages')
return 'anthropic-sse';
// The Maka arm dials whatever wire its own runtime resolves, so that runtime
// is the authority here — the adapter kind is a guess, and a guess that
// drifts is not a gap but a wrong number: when deepseek-v4-flash moved to
// Responses, a proxy still parsing Chat SSE never saw `[DONE]`, recorded
// every request `interrupted` with no usage, and the runner threw each
// graded cell away as an infra failure.
//
// Which model is not optional information for the Maka arm: without it there
// is nothing to ask the runtime and the answer silently degrades back to the
// guess. Say so rather than returning a plausible wrong number. The id is
// normalized here so a caller passing the catalog spelling cannot resolve a
// different wire than the one the runtime dials — `resolveModelRuntime`
// does not recognize `deepseek/deepseek-v4-flash` and falls back to Chat.
if (agent === 'maka') {
if (!modelId) throw new Error('providerProxyUsageProtocol: the maka arm requires a model id');
const wire = makaRuntimeWire(provider, modelIdForProvider(modelId, provider), apiProtocol);
if (wire) return usageProtocolForWire(wire);
}
const definition = providerDefinition(provider);
if (definition?.runtimeAdapter.kind === 'anthropic') return 'anthropic-sse';
if (definition?.runtimeAdapter.kind === 'openai-compatible') return 'openai-chat-sse';
return undefined;
}

function makaRuntimeWire(
provider: string,
modelId: string,
apiProtocol?: string,
): ModelRuntimeWire | null {
if (!providerDefinition(provider)) return null;
// The connection the runtime will actually build, not one this side invents:
// an advertised protocol only reaches the model entry for the providers whose
// connections carry it, and `selectedModelApiProtocol` is where that is
// decided. Honouring it here where the runtime drops it would resolve a wire
// nothing dials — the wrong-number failure this whole path exists to remove.
const advertised = selectedModelApiProtocol(
provider as ProviderType,
modelApiProtocolFromEnv(apiProtocol),
);
return resolveModelRuntime(
{
providerType: provider as ProviderType,
...(advertised ? { models: [{ id: modelId, apiProtocol: advertised }] } : {}),
},
modelId,
).wire;
}

function usageProtocolForWire(wire: ModelRuntimeWire): ProviderUsageProtocol | undefined {
if (wire === 'anthropic-messages') return 'anthropic-sse';
if (wire === 'openai-chat') return 'openai-chat-sse';
if (wire === 'openai-responses') return 'openai-responses-sse';
return undefined;
}

function providerDefinition(provider: string) {
return (PROVIDER_DEFAULTS as Partial<Record<string, (typeof PROVIDER_DEFAULTS)[ProviderType]>>)[
provider
Expand Down
2 changes: 1 addition & 1 deletion packages/headless/src/pier-task-runner.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -915,7 +915,7 @@ async function pierProviderRuntime(
: { apiKeyFile: options.apiKeyFile! }),
clientAuthMode: providerProxyClientAuthMode(agent, provider, apiProtocol),
upstreamAuthMode: providerProxyUpstreamAuthMode(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol),
usageProtocol: providerProxyUsageProtocol(agent, provider, apiProtocol, options.model),
};
const proxy =
options.providerProxyHub && proxyPort !== undefined
Expand Down
27 changes: 24 additions & 3 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,6 +9,28 @@ import {
} from '@maka/core';
import type { RunHarborCellEnv } from './headless-run-env.js';

/**
* The protocol a connection actually carries, given what was advertised.
*
* Only two providers let an advertised protocol pick the wire: GitHub Copilot,
* where the account discovers it, and the Kimi Coding Plan, which is sold as
* two protocols against one account. Everywhere else the model's own catalog
* entry decides, and an advertised value is dropped.
*
* Anything deciding what wire the Maka runtime will dial has to apply this same
* rule, or it decides about a connection the runtime will never build. The
* proxy resolves its SSE parser that way (`providerProxyUsageProtocol`), and
* honouring the override where the runtime drops it is the same wrong-wire
* failure — a proxy parsing Chat while the runtime dials Responses records
* every request interrupted with no usage.
*/
export function selectedModelApiProtocol(
provider: ProviderType,
advertised: ModelInfo['apiProtocol'],
): ModelInfo['apiProtocol'] {
return provider === 'github-copilot' || provider === 'kimi-coding-plan' ? advertised : undefined;
}

export interface ProviderCredentialEnv {
apiKeys: readonly string[];
apiKeyFile: string;
Expand DownExpand Up@@ -218,8 +240,7 @@ function connectionFromEnv(
if (provider === 'github-copilot' && !modelApiProtocol) {
throw new Error('GitHub Copilot requires an account-discovered model protocol');
}
const selectedApiProtocol =
provider === 'github-copilot' || provider === 'kimi-coding-plan' ? modelApiProtocol : undefined;
const selectedApiProtocol = selectedModelApiProtocol(provider, modelApiProtocol);
return {
slug: values.MAKA_LLM_CONNECTION_SLUG ?? provider,
name: defaults.label,
Expand All@@ -237,7 +258,7 @@ function connectionFromEnv(
};
}

function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
export function modelApiProtocolFromEnv(value: string | undefined): ModelInfo['apiProtocol'] {
if (value === 'openai-chat' || value === 'openai-responses' || value === 'anthropic-messages')
return value;
return undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@
"./tool-output-delta": "./dist/tool-output-delta.js",
"./stream-watchdog": "./dist/stream-watchdog.js",
"./model-factory": "./dist/model-factory.js",
"./model-runtime": "./dist/model-runtime.js",
"./context-budget": "./dist/context-budget.js",
"./active-full-compact": "./dist/active-full-compact.js",
"./semantic-compact": "./dist/semantic-compact.js",
Expand Down
Loading