107 lines
3.3 KiB
TypeScript
Raw Normal View History

2026-01-14 01:08:15 +00:00
import type { StreamFn } from "@mariozechner/pi-agent-core";
import type { Api, Model, SimpleStreamOptions } from "@mariozechner/pi-ai";
import { streamSimple } from "@mariozechner/pi-ai";
import type { ClawdbotConfig } from "../../config/config.js";
import { log } from "./logger.js";
/**
2026-01-16 22:25:51 +00:00
* Resolve provider-specific extra params from model config.
* Used to pass through stream params like temperature/maxTokens.
2026-01-14 01:08:15 +00:00
*
* @internal Exported for testing only
*/
export function resolveExtraParams(params: {
cfg: ClawdbotConfig | undefined;
provider: string;
modelId: string;
}): Record<string, unknown> | undefined {
const modelKey = `${params.provider}/${params.modelId}`;
const modelConfig = params.cfg?.agents?.defaults?.models?.[modelKey];
2026-01-16 22:25:51 +00:00
return modelConfig?.params ? { ...modelConfig.params } : undefined;
2026-01-14 01:08:15 +00:00
}
2026-01-21 19:44:20 +00:00
type CacheControlTtl = "5m";
function resolveCacheControlTtl(
extraParams: Record<string, unknown> | undefined,
provider: string,
modelId: string,
): CacheControlTtl | undefined {
const raw = extraParams?.cacheControlTtl;
2026-01-21 19:44:20 +00:00
if (raw !== "5m") return undefined;
if (provider === "anthropic") return raw;
if (provider === "openrouter" && modelId.startsWith("anthropic/")) return raw;
return undefined;
}
2026-01-14 01:08:15 +00:00
function createStreamFnWithExtraParams(
baseStreamFn: StreamFn | undefined,
extraParams: Record<string, unknown> | undefined,
provider: string,
modelId: string,
2026-01-14 01:08:15 +00:00
): StreamFn | undefined {
if (!extraParams || Object.keys(extraParams).length === 0) {
return undefined;
}
const streamParams: Partial<SimpleStreamOptions> & { cacheControlTtl?: CacheControlTtl } = {};
2026-01-14 01:08:15 +00:00
if (typeof extraParams.temperature === "number") {
streamParams.temperature = extraParams.temperature;
}
if (typeof extraParams.maxTokens === "number") {
streamParams.maxTokens = extraParams.maxTokens;
}
const cacheControlTtl = resolveCacheControlTtl(extraParams, provider, modelId);
if (cacheControlTtl) {
streamParams.cacheControlTtl = cacheControlTtl;
}
2026-01-14 01:08:15 +00:00
if (Object.keys(streamParams).length === 0) {
return undefined;
}
log.debug(`creating streamFn wrapper with params: ${JSON.stringify(streamParams)}`);
2026-01-14 01:08:15 +00:00
const underlying = baseStreamFn ?? streamSimple;
const wrappedStreamFn: StreamFn = (model, context, options) =>
underlying(model as Model<Api>, context, {
...streamParams,
...options,
});
return wrappedStreamFn;
}
/**
* Apply extra params (like temperature) to an agent's streamFn.
*
* @internal Exported for testing
*/
export function applyExtraParamsToAgent(
agent: { streamFn?: StreamFn },
cfg: ClawdbotConfig | undefined,
provider: string,
modelId: string,
extraParamsOverride?: Record<string, unknown>,
2026-01-14 01:08:15 +00:00
): void {
const extraParams = resolveExtraParams({
cfg,
provider,
modelId,
});
const override =
extraParamsOverride && Object.keys(extraParamsOverride).length > 0
? Object.fromEntries(
Object.entries(extraParamsOverride).filter(([, value]) => value !== undefined),
)
: undefined;
const merged = Object.assign({}, extraParams, override);
const wrappedStreamFn = createStreamFnWithExtraParams(agent.streamFn, merged, provider, modelId);
2026-01-14 01:08:15 +00:00
if (wrappedStreamFn) {
log.debug(`applying extraParams to agent streamFn for ${provider}/${modelId}`);
2026-01-14 01:08:15 +00:00
agent.streamFn = wrappedStreamFn;
}
}