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 { services } from "../services/index.js";
|
||||||
import { streamChatResponse } from "../stream/streamChatResponse.js";
|
import { streamChatResponse } from "../stream/streamChatResponse.js";
|
||||||
import { StreamCallbacks } from "../stream/streamChatResponse.types.js";
|
import { StreamCallbacks } from "../stream/streamChatResponse.types.js";
|
||||||
import { logger } from "../util/logger.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
|
// Modified version of streamChatResponse that supports interruption
|
||||||
export async function streamChatResponseWithInterruption(
|
export async function streamChatResponseWithInterruption(
|
||||||
state: ServerState,
|
state: ServerState,
|
||||||
@@ -124,3 +149,21 @@ export interface ServerState {
|
|||||||
pendingPermission: PendingPermission | null;
|
pendingPermission: PendingPermission | null;
|
||||||
systemMessage?: string;
|
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 { ExtendedCommandOptions } from "./BaseCommandOptions.js";
|
||||||
import {
|
import {
|
||||||
|
checkAgentComplete,
|
||||||
|
removePartialAssistantMessage,
|
||||||
streamChatResponseWithInterruption,
|
streamChatResponseWithInterruption,
|
||||||
type ServerState,
|
type ServerState,
|
||||||
} from "./serve.helpers.js";
|
} 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) {
|
async function processMessages(state: ServerState, llmApi: any) {
|
||||||
let processedMessage = false;
|
let processedMessage = false;
|
||||||
while (state.serverRunning) {
|
while (state.serverRunning) {
|
||||||
@@ -529,21 +509,11 @@ export async function serve(prompt?: string, options: ServeOptions = {}) {
|
|||||||
// Update metadata after successful agent turn
|
// Update metadata after successful agent turn
|
||||||
try {
|
try {
|
||||||
const history = services.chatHistory?.getHistory();
|
const history = services.chatHistory?.getHistory();
|
||||||
|
await updateAgentMetadata({
|
||||||
// Check if the agent should be marked as complete
|
history,
|
||||||
// The agent is complete if the last message is from the assistant and has no tool calls
|
isComplete: checkAgentComplete(history),
|
||||||
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 });
|
|
||||||
} catch (metadataErr) {
|
} catch (metadataErr) {
|
||||||
// Non-critical: log but don't fail the agent execution
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Failed to update metadata after turn (non-critical)",
|
"Failed to update metadata after turn (non-critical)",
|
||||||
metadataErr as any,
|
metadataErr as any,
|
||||||
@@ -552,8 +522,7 @@ export async function serve(prompt?: string, options: ServeOptions = {}) {
|
|||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e.name === "AbortError") {
|
if (e.name === "AbortError") {
|
||||||
logger.debug("Response interrupted");
|
logger.debug("Response interrupted");
|
||||||
// Remove any partial assistant message
|
removePartialAssistantMessage(state.session.history);
|
||||||
removePartialAssistantMessage(state);
|
|
||||||
} else {
|
} else {
|
||||||
logger.error(`Error: ${formatError(e)}`);
|
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 type { ChatHistoryItem } from "core/index.js";
|
||||||
|
|
||||||
|
import { env } from "../env.js";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
post,
|
post,
|
||||||
ApiRequestError,
|
ApiRequestError,
|
||||||
@@ -124,6 +126,9 @@ export async function postAgentMetadata(
|
|||||||
agentId: string,
|
agentId: string,
|
||||||
metadata: Record<string, any>,
|
metadata: Record<string, any>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const endpoint = `agents/${agentId}/metadata`;
|
||||||
|
const fullUrl = new URL(endpoint, env.apiBase).toString();
|
||||||
|
|
||||||
if (!agentId) {
|
if (!agentId) {
|
||||||
logger.debug("No agent ID provided, skipping metadata update");
|
logger.debug("No agent ID provided, skipping metadata update");
|
||||||
return;
|
return;
|
||||||
@@ -134,36 +139,44 @@ export async function postAgentMetadata(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
const startTime = Date.now();
|
||||||
logger.debug("Posting metadata to control plane", {
|
logger.info(`[metadata] POST ${fullUrl}`, {
|
||||||
agentId,
|
agentId,
|
||||||
metadata,
|
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) {
|
if (response.ok) {
|
||||||
logger.info("Successfully posted metadata to control plane");
|
logger.info(
|
||||||
|
`[metadata] Success: ${response.status} (${duration}ms) ${fullUrl}`,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`Unexpected response when posting metadata: ${response.status}`,
|
`[metadata] Unexpected response: ${response.status} (${duration}ms) ${fullUrl}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const duration = Date.now() - startTime;
|
||||||
// Non-critical: Log but don't fail the entire agent execution
|
// Non-critical: Log but don't fail the entire agent execution
|
||||||
if (error instanceof AuthenticationRequiredError) {
|
if (error instanceof AuthenticationRequiredError) {
|
||||||
logger.debug(
|
logger.info(
|
||||||
"Authentication required for metadata update (skipping)",
|
`[metadata] Auth required (skipping) (${duration}ms) ${fullUrl}`,
|
||||||
error.message,
|
|
||||||
);
|
);
|
||||||
} else if (error instanceof ApiRequestError) {
|
} else if (error instanceof ApiRequestError) {
|
||||||
logger.warn(
|
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 {
|
} else {
|
||||||
const errorMessage =
|
const errorMessage =
|
||||||
error instanceof Error ? error.message : String(error);
|
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