v2.3.0-sampling-params-ask-user: agent sampling params, ask_user_input in CoderPane, UX polish
Add top_p/top_k/min_p/presence_penalty to AGENTS.md frontmatter and thread through inference (agents.ts parser → Agent type → stream-phase → sentinel summaries). Null means omit from request body, preserving provider defaults. Wire ask_user_input interactive card into both BooCoder frontends: the CoderPane in BooChat's SPA (CoderMessageList now renders AskUserInputCard instead of ToolCallLine for ask_user_input tool calls) and the standalone coder SPA (MessageBubble + new AskUserInputCard + shadcn ui primitives). Additional fixes: SessionLandingPage uses ChatInput with slash-command support and lazy chat creation; Session.tsx hydrate-race fix for empty pane promotion; AgentPicker wider dropdown with line-clamp; ModelPicker min-width; Textarea converted to forwardRef; Recon agent added to AGENTS.md; codecontext host port exposed in docker-compose. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -83,6 +83,10 @@ export function slugify(name: string): string {
|
||||
|
||||
interface ParsedFrontmatter {
|
||||
temperature?: number;
|
||||
top_p?: number;
|
||||
top_k?: number;
|
||||
min_p?: number;
|
||||
presence_penalty?: number;
|
||||
tools?: string[];
|
||||
description?: string;
|
||||
model?: string;
|
||||
@@ -132,6 +136,46 @@ function parseFrontmatter(yaml: string): { data: ParsedFrontmatter; errors: stri
|
||||
const n = Number(valueRaw);
|
||||
if (Number.isFinite(n)) data.temperature = n;
|
||||
else errors.push(`temperature must be a number (got "${valueRaw}")`);
|
||||
} else if (key === 'top_p') {
|
||||
const n = Number(valueRaw);
|
||||
if (Number.isFinite(n)) {
|
||||
data.top_p = n;
|
||||
if (n < 0 || n > 1) {
|
||||
console.warn(`agents: top_p ${n} out of range 0-1, ignoring (falling back to default)`);
|
||||
}
|
||||
} else {
|
||||
errors.push(`top_p must be a number (got "${valueRaw}")`);
|
||||
}
|
||||
} else if (key === 'top_k') {
|
||||
const n = Number(valueRaw);
|
||||
if (Number.isInteger(n)) {
|
||||
data.top_k = n;
|
||||
if (n < 0 || n > 200) {
|
||||
console.warn(`agents: top_k ${n} out of range 0-200, ignoring (falling back to default)`);
|
||||
}
|
||||
} else {
|
||||
errors.push(`top_k must be an integer (got "${valueRaw}")`);
|
||||
}
|
||||
} else if (key === 'min_p') {
|
||||
const n = Number(valueRaw);
|
||||
if (Number.isFinite(n)) {
|
||||
data.min_p = n;
|
||||
if (n < 0 || n > 1) {
|
||||
console.warn(`agents: min_p ${n} out of range 0-1, ignoring (falling back to default)`);
|
||||
}
|
||||
} else {
|
||||
errors.push(`min_p must be a number (got "${valueRaw}")`);
|
||||
}
|
||||
} else if (key === 'presence_penalty') {
|
||||
const n = Number(valueRaw);
|
||||
if (Number.isFinite(n)) {
|
||||
data.presence_penalty = n;
|
||||
if (n < -2 || n > 2) {
|
||||
console.warn(`agents: presence_penalty ${n} out of range -2-2, ignoring (falling back to default)`);
|
||||
}
|
||||
} else {
|
||||
errors.push(`presence_penalty must be a number (got "${valueRaw}")`);
|
||||
}
|
||||
} else if (key === 'tools') {
|
||||
if (valueRaw === '') {
|
||||
data.tools = [];
|
||||
@@ -276,6 +320,10 @@ function parseAgentSection(section: RawSection): Omit<Agent, 'source'> {
|
||||
description: fm.description ?? '',
|
||||
system_prompt: systemPrompt,
|
||||
temperature: typeof fm.temperature === 'number' ? fm.temperature : DEFAULT_TEMPERATURE,
|
||||
top_p: typeof fm.top_p === 'number' ? fm.top_p : null,
|
||||
top_k: typeof fm.top_k === 'number' ? fm.top_k : null,
|
||||
min_p: typeof fm.min_p === 'number' ? fm.min_p : null,
|
||||
presence_penalty: typeof fm.presence_penalty === 'number' ? fm.presence_penalty : null,
|
||||
tools: filteredTools,
|
||||
model: typeof fm.model === 'string' && fm.model.length > 0 ? fm.model : null,
|
||||
max_tool_calls: typeof fm.max_tool_calls === 'number' ? fm.max_tool_calls : null,
|
||||
|
||||
@@ -86,7 +86,7 @@ export async function runCapHitSummary(
|
||||
ctx,
|
||||
session.model,
|
||||
messages,
|
||||
{ tools: null, temperature: agent?.temperature },
|
||||
{ tools: null, temperature: agent?.temperature, top_p: agent?.top_p ?? undefined, top_k: agent?.top_k ?? undefined, min_p: agent?.min_p ?? undefined, presence_penalty: agent?.presence_penalty ?? undefined },
|
||||
(delta) => {
|
||||
accumulated += delta;
|
||||
ctx.publish(sessionId, {
|
||||
@@ -346,7 +346,7 @@ export async function runDoomLoopSummary(
|
||||
ctx,
|
||||
session.model,
|
||||
messages,
|
||||
{ tools: null, temperature: agent?.temperature },
|
||||
{ tools: null, temperature: agent?.temperature, top_p: agent?.top_p ?? undefined, top_k: agent?.top_k ?? undefined, min_p: agent?.min_p ?? undefined, presence_penalty: agent?.presence_penalty ?? undefined },
|
||||
(delta) => {
|
||||
accumulated += delta;
|
||||
ctx.publish(sessionId, {
|
||||
@@ -545,7 +545,7 @@ export async function runStepCapSummary(
|
||||
ctx,
|
||||
session.model,
|
||||
messages,
|
||||
{ tools: null, temperature: agent?.temperature },
|
||||
{ tools: null, temperature: agent?.temperature, top_p: agent?.top_p ?? undefined, top_k: agent?.top_k ?? undefined, min_p: agent?.min_p ?? undefined, presence_penalty: agent?.presence_penalty ?? undefined },
|
||||
(delta) => {
|
||||
accumulated += delta;
|
||||
ctx.publish(sessionId, {
|
||||
|
||||
@@ -31,6 +31,10 @@ interface StreamOptions {
|
||||
// (rare; we still omit from the request body to avoid OpenAI 400).
|
||||
tools: ToolJsonSchema[] | null;
|
||||
temperature?: number;
|
||||
top_p?: number | null;
|
||||
top_k?: number | null;
|
||||
min_p?: number | null;
|
||||
presence_penalty?: number | null;
|
||||
}
|
||||
|
||||
// v1.13.1-A: convert BooCode's OpenAI-shaped history into AI SDK
|
||||
@@ -199,6 +203,9 @@ export async function streamCompletion(
|
||||
? { tools: aiTools, toolChoice: 'auto' as const, experimental_repairToolCall: repairToolCall }
|
||||
: {}),
|
||||
...(typeof opts.temperature === 'number' ? { temperature: opts.temperature } : {}),
|
||||
...(typeof opts.top_p === 'number' ? { topP: opts.top_p } : {}),
|
||||
...(typeof opts.top_k === 'number' ? { topK: opts.top_k } : {}),
|
||||
...(typeof opts.presence_penalty === 'number' ? { presencePenalty: opts.presence_penalty } : {}),
|
||||
abortSignal: signal,
|
||||
});
|
||||
|
||||
@@ -388,6 +395,10 @@ export async function executeStreamPhase(
|
||||
: toolJsonSchemas()
|
||||
).filter((t) => webToolsEnabled || !WEB_TOOL_NAMES.has(t.function.name));
|
||||
const effectiveTemperature = agent?.temperature;
|
||||
const effectiveTopP = agent?.top_p ?? undefined;
|
||||
const effectiveTopK = agent?.top_k ?? undefined;
|
||||
const effectiveMinP = agent?.min_p ?? undefined;
|
||||
const effectivePresencePenalty = agent?.presence_penalty ?? undefined;
|
||||
|
||||
// v1.12.2: ctx_max lookup is cached after the first hit per model, so this
|
||||
// is a Map probe in steady state. We capture nCtx once at the top of the
|
||||
@@ -425,7 +436,7 @@ export async function executeStreamPhase(
|
||||
ctx,
|
||||
session.model,
|
||||
messages,
|
||||
{ tools: effectiveTools, temperature: effectiveTemperature },
|
||||
{ tools: effectiveTools, temperature: effectiveTemperature, top_p: effectiveTopP, top_k: effectiveTopK, min_p: effectiveMinP, presence_penalty: effectivePresencePenalty },
|
||||
(delta) => {
|
||||
state.accumulated += delta;
|
||||
ctx.publish(sessionId, {
|
||||
|
||||
Reference in New Issue
Block a user