Merge pull request #9909 from continuedev/nate/fixes-4888
Add detailed logging for metadata endpoint requests
This commit is contained in:
@@ -1,10 +1,35 @@
|
||||
import type { Session, ToolStatus } from "core/index.js";
|
||||
import type { ChatHistoryItem, Session, ToolStatus } from "core/index.js";
|
||||
|
||||
import { services } from "../services/index.js";
|
||||
import { streamChatResponse } from "../stream/streamChatResponse.js";
|
||||
import { StreamCallbacks } from "../stream/streamChatResponse.types.js";
|
||||
import { logger } from "../util/logger.js";
|
||||
|
||||
/**
|
||||
* Remove partial assistant message if the last message is an empty assistant message.
|
||||
* Used when a response is interrupted.
|
||||
*/
|
||||
export function removePartialAssistantMessage(
|
||||
sessionHistory: ChatHistoryItem[],
|
||||
): void {
|
||||
try {
|
||||
const svcHistory = services.chatHistory.getHistory();
|
||||
const last = svcHistory[svcHistory.length - 1];
|
||||
if (last && last.message.role === "assistant" && !last.message.content) {
|
||||
services.chatHistory.setHistory(svcHistory.slice(0, -1));
|
||||
}
|
||||
} catch {
|
||||
const lastMessage = sessionHistory[sessionHistory.length - 1];
|
||||
if (
|
||||
lastMessage &&
|
||||
lastMessage.message.role === "assistant" &&
|
||||
!lastMessage.message.content
|
||||
) {
|
||||
sessionHistory.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modified version of streamChatResponse that supports interruption
|
||||
export async function streamChatResponseWithInterruption(
|
||||
state: ServerState,
|
||||
@@ -124,3 +149,21 @@ export interface ServerState {
|
||||
pendingPermission: PendingPermission | null;
|
||||
systemMessage?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the agent should be marked as complete based on conversation history.
|
||||
* The agent is complete if the last message is from the assistant and has no tool calls.
|
||||
*/
|
||||
export function checkAgentComplete(
|
||||
history: { message: { role: string; tool_calls?: any[] } }[] | undefined,
|
||||
): boolean {
|
||||
if (!history || history.length === 0) {
|
||||
return false;
|
||||
}
|
||||
const lastItem = history[history.length - 1];
|
||||
if (lastItem?.message?.role !== "assistant") {
|
||||
return false;
|
||||
}
|
||||
const toolCalls = (lastItem.message as any).tool_calls;
|
||||
return !toolCalls || toolCalls.length === 0;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ import { readStdinSync } from "../util/stdin.js";
|
||||
|
||||
import { ExtendedCommandOptions } from "./BaseCommandOptions.js";
|
||||
import {
|
||||
checkAgentComplete,
|
||||
removePartialAssistantMessage,
|
||||
streamChatResponseWithInterruption,
|
||||
type ServerState,
|
||||
} from "./serve.helpers.js";
|
||||
@@ -464,28 +466,6 @@ export async function serve(prompt?: string, options: ServeOptions = {}) {
|
||||
}
|
||||
});
|
||||
|
||||
// Process messages from the queue
|
||||
function removePartialAssistantMessage(state: ServerState) {
|
||||
try {
|
||||
const svcHistory = services.chatHistory.getHistory();
|
||||
const last = svcHistory[svcHistory.length - 1];
|
||||
if (last && last.message.role === "assistant" && !last.message.content) {
|
||||
const trimmed = svcHistory.slice(0, -1);
|
||||
services.chatHistory.setHistory(trimmed);
|
||||
}
|
||||
} catch {
|
||||
const lastMessage =
|
||||
state.session.history[state.session.history.length - 1];
|
||||
if (
|
||||
lastMessage &&
|
||||
lastMessage.message.role === "assistant" &&
|
||||
!lastMessage.message.content
|
||||
) {
|
||||
state.session.history.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function processMessages(state: ServerState, llmApi: any) {
|
||||
let processedMessage = false;
|
||||
while (state.serverRunning) {
|
||||
@@ -529,21 +509,11 @@ export async function serve(prompt?: string, options: ServeOptions = {}) {
|
||||
// Update metadata after successful agent turn
|
||||
try {
|
||||
const history = services.chatHistory?.getHistory();
|
||||
|
||||
// Check if the agent should be marked as complete
|
||||
// The agent is complete if the last message is from the assistant and has no tool calls
|
||||
let isComplete = false;
|
||||
if (history && history.length > 0) {
|
||||
const lastItem = history[history.length - 1];
|
||||
if (lastItem?.message?.role === "assistant") {
|
||||
const toolCalls = (lastItem.message as any).tool_calls;
|
||||
isComplete = !toolCalls || toolCalls.length === 0;
|
||||
}
|
||||
}
|
||||
|
||||
await updateAgentMetadata({ history, isComplete });
|
||||
await updateAgentMetadata({
|
||||
history,
|
||||
isComplete: checkAgentComplete(history),
|
||||
});
|
||||
} catch (metadataErr) {
|
||||
// Non-critical: log but don't fail the agent execution
|
||||
logger.debug(
|
||||
"Failed to update metadata after turn (non-critical)",
|
||||
metadataErr as any,
|
||||
@@ -552,8 +522,7 @@ export async function serve(prompt?: string, options: ServeOptions = {}) {
|
||||
} catch (e: any) {
|
||||
if (e.name === "AbortError") {
|
||||
logger.debug("Response interrupted");
|
||||
// Remove any partial assistant message
|
||||
removePartialAssistantMessage(state);
|
||||
removePartialAssistantMessage(state.session.history);
|
||||
} else {
|
||||
logger.error(`Error: ${formatError(e)}`);
|
||||
|
||||
@@ -655,7 +624,3 @@ export async function serve(prompt?: string, options: ServeOptions = {}) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Function moved to serve.helpers.ts - remove implementation
|
||||
// async function streamChatResponseWithInterruption - moved to helpers {
|
||||
// Implementation moved to serve.helpers.ts
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { ChatHistoryItem } from "core/index.js";
|
||||
|
||||
import { env } from "../env.js";
|
||||
|
||||
import {
|
||||
post,
|
||||
ApiRequestError,
|
||||
@@ -124,6 +126,9 @@ export async function postAgentMetadata(
|
||||
agentId: string,
|
||||
metadata: Record<string, any>,
|
||||
): Promise<void> {
|
||||
const endpoint = `agents/${agentId}/metadata`;
|
||||
const fullUrl = new URL(endpoint, env.apiBase).toString();
|
||||
|
||||
if (!agentId) {
|
||||
logger.debug("No agent ID provided, skipping metadata update");
|
||||
return;
|
||||
@@ -134,36 +139,44 @@ export async function postAgentMetadata(
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
logger.debug("Posting metadata to control plane", {
|
||||
agentId,
|
||||
metadata,
|
||||
});
|
||||
const startTime = Date.now();
|
||||
logger.info(`[metadata] POST ${fullUrl}`, {
|
||||
agentId,
|
||||
metadataKeys: Object.keys(metadata),
|
||||
});
|
||||
logger.info("[metadata] Request body", { metadata });
|
||||
|
||||
const response = await post(`agents/${agentId}/metadata`, { metadata });
|
||||
try {
|
||||
const response = await post(endpoint, { metadata });
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
if (response.ok) {
|
||||
logger.info("Successfully posted metadata to control plane");
|
||||
logger.info(
|
||||
`[metadata] Success: ${response.status} (${duration}ms) ${fullUrl}`,
|
||||
);
|
||||
} else {
|
||||
logger.warn(
|
||||
`Unexpected response when posting metadata: ${response.status}`,
|
||||
`[metadata] Unexpected response: ${response.status} (${duration}ms) ${fullUrl}`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
const duration = Date.now() - startTime;
|
||||
// Non-critical: Log but don't fail the entire agent execution
|
||||
if (error instanceof AuthenticationRequiredError) {
|
||||
logger.debug(
|
||||
"Authentication required for metadata update (skipping)",
|
||||
error.message,
|
||||
logger.info(
|
||||
`[metadata] Auth required (skipping) (${duration}ms) ${fullUrl}`,
|
||||
);
|
||||
} else if (error instanceof ApiRequestError) {
|
||||
logger.warn(
|
||||
`Failed to post metadata: ${error.status} ${error.response || error.statusText}`,
|
||||
`[metadata] Failed: ${error.status} ${error.statusText} (${duration}ms) ${fullUrl}`,
|
||||
{ response: error.response },
|
||||
);
|
||||
} else {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : String(error);
|
||||
logger.warn(`Error posting metadata: ${errorMessage}`);
|
||||
logger.warn(
|
||||
`[metadata] Error: ${errorMessage} (${duration}ms) ${fullUrl}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user