Improve runtime status clarity and direct answers
--- Build: pass | Tests: FAIL — Tests 1 failed | 2043 passed (2044)
This commit is contained in:
parent
29c472f7f7
commit
de88930ffd
5 changed files with 118 additions and 16 deletions
|
|
@ -415,6 +415,7 @@ export async function runJailAgent(
|
|||
const runtimeInfo =
|
||||
`Rule: Your current LLM runtime is provider=${effectiveProvider || 'unknown'}, model=${effectiveModel || 'unknown'}. ` +
|
||||
`State this accurately if asked — do not guess or substitute another model name.\n` +
|
||||
`Rule: Do not end your reply with a promise of future inspection or follow-up unless you are actually providing that follow-up in the same message. If there is no real async job, answer directly now.\n` +
|
||||
`Rule: The Mevy service runs as a FreeBSD rc.d service and executes \`node dist/index.js\` (not \`node src/index.ts\`). ` +
|
||||
`Do not tell the operator to run \`just dev\` or start the service manually unless explicitly asked; instead, instruct to check \`sudo service ${PLATFORM_SERVICE_NAME} status\` and use \`sudo service ${PLATFORM_SERVICE_NAME} restart\` when needed.\n` +
|
||||
`Rule: Text-to-speech uses the \`edge-tts\` CLI provided by the repo wrapper at \`/home/mevy/mevy-ai/bin/edge-tts\`, which runs from a persistent uv venv at \`/home/mevy/mevy-ai/.venv-edge-tts\`. ` +
|
||||
|
|
|
|||
|
|
@ -38,4 +38,11 @@ describe('pi-profile', () => {
|
|||
expect(prompt).toContain('customer-safe summary');
|
||||
expect(prompt).toContain('Session policy: persistent');
|
||||
});
|
||||
|
||||
it('teaches operator mode to answer directly instead of promising follow-up', () => {
|
||||
const profile = resolvePiTuiProfile({ profile: 'operator' });
|
||||
const prompt = buildPiTuiProfilePrompt(profile.name, profile);
|
||||
expect(prompt).toContain('Do not reply with placeholder lines like "let me inspect"');
|
||||
expect(prompt).toContain('If you can answer now, answer now.');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ export const PI_TUI_PROFILES: Record<PiTuiProfileName, PiTuiProfileDefinition> =
|
|||
'Stay concise and operational.',
|
||||
'Prefer immediate fixes over long explanations.',
|
||||
'Always end your turn with a visible text reply. Never finish with only a thinking block — your final output must be readable text.',
|
||||
'Do not reply with placeholder lines like "let me inspect" or "I will check" unless the findings are included in the same reply. If you can answer now, answer now.',
|
||||
],
|
||||
},
|
||||
status: {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { describe, it, expect, beforeEach } from 'vitest';
|
|||
|
||||
import {
|
||||
augmentPickerModels,
|
||||
buildStatusRuntimeLines,
|
||||
getTtsModeForChat,
|
||||
setTtsModeForChat,
|
||||
clearTtsOverride,
|
||||
|
|
@ -200,3 +201,40 @@ describe('augmentPickerModels', () => {
|
|||
expect(models.map((m) => m.id)).toEqual(['openai/o3']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildStatusRuntimeLines', () => {
|
||||
it('shows default, chat override, heartbeat override, and drift clearly', () => {
|
||||
const lines = buildStatusRuntimeLines({
|
||||
defaultProvider: 'deepseek',
|
||||
defaultModel: 'deepseek-chat',
|
||||
heartbeatProvider: 'deepseek',
|
||||
heartbeatModel: 'deepseek-v4-flash',
|
||||
overrideProvider: 'openrouter',
|
||||
overrideModel: 'openai/o3',
|
||||
actualProvider: 'deepseek',
|
||||
actualModel: 'deepseek-chat',
|
||||
});
|
||||
|
||||
expect(lines).toEqual([
|
||||
'Default runtime: <code>deepseek/deepseek-chat</code>',
|
||||
'Chat runtime: <code>openrouter/openai/o3</code> (override)',
|
||||
'Heartbeat runtime: <code>deepseek/deepseek-v4-flash</code>',
|
||||
'Last actual: <code>deepseek/deepseek-chat</code> ⚠ drift',
|
||||
]);
|
||||
});
|
||||
|
||||
it('shows a default-backed chat runtime when there is no override', () => {
|
||||
const lines = buildStatusRuntimeLines({
|
||||
defaultProvider: 'deepseek',
|
||||
defaultModel: 'deepseek-chat',
|
||||
actualProvider: 'deepseek',
|
||||
actualModel: 'deepseek-chat',
|
||||
});
|
||||
|
||||
expect(lines).toEqual([
|
||||
'Default runtime: <code>deepseek/deepseek-chat</code>',
|
||||
'Chat runtime: <code>deepseek/deepseek-chat</code> (default)',
|
||||
'Last actual: <code>deepseek/deepseek-chat</code>',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ import {
|
|||
AGENT_BUDGET_PAUSE_PCT,
|
||||
ASSISTANT_NAME,
|
||||
CMS_WEBROOT,
|
||||
HEARTBEAT_MODEL,
|
||||
HEARTBEAT_PROVIDER,
|
||||
PLATFORM_ID,
|
||||
PLATFORM_SERVICE_NAME,
|
||||
PI_TUI_MODEL,
|
||||
|
|
@ -231,6 +233,56 @@ function getChatLastActualRuntimeLine(chatJid: string): string | null {
|
|||
return `Last actual runtime: ${provider} / ${model}`;
|
||||
}
|
||||
|
||||
export function buildStatusRuntimeLines(opts: {
|
||||
defaultProvider: string;
|
||||
defaultModel: string;
|
||||
heartbeatProvider?: string;
|
||||
heartbeatModel?: string;
|
||||
overrideProvider?: string;
|
||||
overrideModel?: string;
|
||||
actualProvider?: string;
|
||||
actualModel?: string;
|
||||
}): string[] {
|
||||
const defaultProvider = (opts.defaultProvider || '').trim() || 'default';
|
||||
const defaultModel = (opts.defaultModel || '').trim() || 'default';
|
||||
const overrideProvider = (opts.overrideProvider || '').trim();
|
||||
const overrideModel = (opts.overrideModel || '').trim();
|
||||
const actualProvider = (opts.actualProvider || '').trim();
|
||||
const actualModel = (opts.actualModel || '').trim();
|
||||
const heartbeatProvider = (opts.heartbeatProvider || '').trim();
|
||||
const heartbeatModel = (opts.heartbeatModel || '').trim();
|
||||
|
||||
const effectiveProvider = overrideProvider || defaultProvider;
|
||||
const effectiveModel = overrideModel || defaultModel;
|
||||
const hasOverride = Boolean(overrideProvider || overrideModel);
|
||||
|
||||
const lines = [
|
||||
`Default runtime: <code>${defaultProvider}/${defaultModel}</code>`,
|
||||
`Chat runtime: <code>${effectiveProvider}/${effectiveModel}</code>${hasOverride ? ' (override)' : ' (default)'}`,
|
||||
];
|
||||
|
||||
const effectiveHeartbeatProvider = heartbeatProvider || defaultProvider;
|
||||
const effectiveHeartbeatModel = heartbeatModel || defaultModel;
|
||||
const heartbeatDiffers =
|
||||
effectiveHeartbeatProvider !== defaultProvider ||
|
||||
effectiveHeartbeatModel !== defaultModel;
|
||||
if (heartbeatDiffers) {
|
||||
lines.push(
|
||||
`Heartbeat runtime: <code>${effectiveHeartbeatProvider}/${effectiveHeartbeatModel}</code>`,
|
||||
);
|
||||
}
|
||||
|
||||
if (actualProvider && actualModel) {
|
||||
const drifted =
|
||||
actualProvider !== effectiveProvider || actualModel !== effectiveModel;
|
||||
lines.push(
|
||||
`Last actual: <code>${actualProvider}/${actualModel}</code>${drifted ? ' ⚠ drift' : ''}`,
|
||||
);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
async function replyAuthFailure(ctxArg: any, message: string): Promise<void> {
|
||||
try {
|
||||
if (ctxArg.callbackQuery) {
|
||||
|
|
@ -2004,23 +2056,19 @@ export async function handleStatusCommand(
|
|||
const overrideModel = (group?.jailConfig?.model || '').trim();
|
||||
const actualProvider = (group?.jailConfig?.lastRuntimeProvider || '').trim();
|
||||
const actualModel = (group?.jailConfig?.lastRuntimeModel || '').trim();
|
||||
const hasOverride = Boolean(overrideProvider || overrideModel);
|
||||
const effectiveProvider =
|
||||
overrideProvider || (defaultProvider || '').trim();
|
||||
const effectiveModel = overrideModel || defaultModel;
|
||||
|
||||
if (effectiveProvider) {
|
||||
if (defaultProvider) {
|
||||
lines.push(
|
||||
`Model: <code>${effectiveProvider}/${effectiveModel}</code>${hasOverride ? ' (override)' : ''}`,
|
||||
...buildStatusRuntimeLines({
|
||||
defaultProvider,
|
||||
defaultModel,
|
||||
heartbeatProvider: HEARTBEAT_PROVIDER,
|
||||
heartbeatModel: HEARTBEAT_MODEL,
|
||||
overrideProvider,
|
||||
overrideModel,
|
||||
actualProvider,
|
||||
actualModel,
|
||||
}),
|
||||
);
|
||||
if (hasOverride && defaultProvider) {
|
||||
lines.push(
|
||||
`Default model: <code>${defaultProvider}/${defaultModel}</code>`,
|
||||
);
|
||||
}
|
||||
if (actualProvider && actualModel) {
|
||||
lines.push(`Last actual: <code>${actualProvider}/${actualModel}</code>`);
|
||||
}
|
||||
}
|
||||
|
||||
const active = c.queue.getActiveCount();
|
||||
|
|
@ -2031,7 +2079,14 @@ export async function handleStatusCommand(
|
|||
lines.push(`Groups: ${Object.keys(groups).length} registered`);
|
||||
} else {
|
||||
if (defaultProvider) {
|
||||
lines.push(`Model: <code>${defaultProvider}/${defaultModel}</code>`);
|
||||
lines.push(
|
||||
...buildStatusRuntimeLines({
|
||||
defaultProvider,
|
||||
defaultModel,
|
||||
heartbeatProvider: HEARTBEAT_PROVIDER,
|
||||
heartbeatModel: HEARTBEAT_MODEL,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue