feat: add context overflow detection and automatic history shrinking in agent loop

Implement context manager integration that detects API errors indicating context length exceeded, then automatically shrinks message history and retries the request. Add new messages API functions (remove_range, get_object, replace_at) and a new R_ERROR_CONTEXT_TOO_LONG error code to support this functionality.
This commit is contained in:
retoor 2026-01-28 19:15:02 +00:00
parent 09e3f62a34
commit 216627e777
5 changed files with 62 additions and 1 deletions

View File

@ -17,6 +17,7 @@ SRC_CORE = $(SRCDIR)/r_error.c \
$(SRCDIR)/messages.c \
$(SRCDIR)/agent.c \
$(SRCDIR)/bash_executor.c \
$(SRCDIR)/context_manager.c \
$(SRCDIR)/main.c
SRC_TOOLS = $(TOOLSDIR)/tools_init.c \

View File

@ -21,11 +21,15 @@ r_status_t messages_add_tool_call(messages_handle msgs, struct json_object *mess
r_status_t messages_add_tool_result(messages_handle msgs, const char *tool_call_id, const char *result);
r_status_t messages_remove_last(messages_handle msgs);
r_status_t messages_remove_range(messages_handle msgs, int start, int count);
r_status_t messages_clear(messages_handle msgs);
r_status_t messages_save(messages_handle msgs);
r_status_t messages_load(messages_handle msgs);
struct json_object *messages_get_object(messages_handle msgs, int index);
r_status_t messages_replace_at(messages_handle msgs, int index, struct json_object *message);
struct json_object *messages_to_json(messages_handle msgs);
char *messages_to_string(messages_handle msgs);
int messages_count(messages_handle msgs);

View File

@ -23,6 +23,7 @@ typedef enum {
R_ERROR_TOOL_EXECUTION,
R_ERROR_API_KEY_MISSING,
R_ERROR_API_ERROR,
R_ERROR_CONTEXT_TOO_LONG,
R_ERROR_MAX_ITERATIONS,
R_ERROR_SESSION_INVALID,
R_ERROR_UNKNOWN

View File

@ -4,6 +4,7 @@
#include "http_client.h"
#include "r_config.h"
#include "tool.h"
#include "context_manager.h"
#include <json-c/json.h>
#include <stdio.h>
#include <stdlib.h>
@ -174,7 +175,16 @@ static struct json_object *agent_process_response(agent_handle agent, const char
struct json_object *error_obj;
if (json_object_object_get_ex(parsed, "error", &error_obj)) {
const char *err_str = json_object_to_json_string(error_obj);
fprintf(stderr, "API Error: %s\n", err_str);
// Smart error detection for context overflow
if (strstr(err_str, "too long") ||
strstr(err_str, "context_length_exceeded") ||
strstr(err_str, "Input is too long")) {
agent_set_error(agent, "CONTEXT_OVERFLOW");
} else {
fprintf(stderr, "API Error: %s\n", err_str);
}
json_object_put(parsed);
return NULL;
}
@ -297,6 +307,23 @@ char *agent_run(agent_handle agent, const char *user_message) {
}
struct json_object *choice = agent_process_response(agent, json_data);
if (!choice && agent->last_error && strcmp(agent->last_error, "CONTEXT_OVERFLOW") == 0) {
if (context_manager_shrink(agent->messages) == R_SUCCESS) {
// Retry with shrunk history
free(json_data);
json_data = agent_build_request(agent, NULL, NULL);
agent->state = AGENT_STATE_RUNNING;
// Don't increment iteration_count for retries due to context
agent->iteration_count--;
continue;
} else {
agent_set_error(agent, "Context limit reached and cannot be shrunk further.");
free(json_data);
break;
}
}
free(json_data);
json_data = NULL;

View File

@ -155,6 +155,17 @@ r_status_t messages_remove_last(messages_handle msgs) {
return R_SUCCESS;
}
r_status_t messages_remove_range(messages_handle msgs, int start, int count) {
if (!msgs || !msgs->array) return R_ERROR_INVALID_ARG;
int size = json_object_array_length(msgs->array);
if (start < 0 || start >= size || count < 0) return R_ERROR_INVALID_ARG;
if (start + count > size) count = size - start;
json_object_array_del_idx(msgs->array, start, count);
messages_save(msgs);
return R_SUCCESS;
}
r_status_t messages_clear(messages_handle msgs) {
if (!msgs) return R_ERROR_INVALID_ARG;
@ -220,6 +231,23 @@ r_status_t messages_load(messages_handle msgs) {
return R_SUCCESS;
}
struct json_object *messages_get_object(messages_handle msgs, int index) {
if (!msgs || !msgs->array) return NULL;
return json_object_array_get_idx(msgs->array, index);
}
r_status_t messages_replace_at(messages_handle msgs, int index, struct json_object *message) {
if (!msgs || !msgs->array || !message) return R_ERROR_INVALID_ARG;
int size = json_object_array_length(msgs->array);
if (index < 0 || index >= size) return R_ERROR_INVALID_ARG;
// json-c doesn't have a direct 'replace' for array by index that handles memory easily
// We'll use json_object_array_put_idx which replaces and puts the old object
json_object_array_put_idx(msgs->array, index, message);
messages_save(msgs);
return R_SUCCESS;
}
struct json_object *messages_to_json(messages_handle msgs) {
return msgs ? msgs->array : NULL;
}