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:
parent
09e3f62a34
commit
216627e777
1
Makefile
1
Makefile
@ -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 \
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
29
src/agent.c
29
src/agent.c
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user