mirror of
https://github.com/openai/codex.git
synced 2026-11-11 21:10:39 +00:00
## Why Dedicated memories tools are exposed through a Responses API namespace tool. The namespace itself has to be a valid tool identifier, so `memories/` can fail validation before the model ever gets a chance to call the memory tools. ## What changed - Changed `MEMORY_TOOLS_NAMESPACE` from `memories/` to `memories`. - Added `memory_tool_namespace_matches_responses_api_identifier` so the namespace stays non-empty and limited to Responses-safe identifier characters. ## Verification - Added unit coverage for the namespace identifier shape in `codex-rs/ext/memories/src/tests.rs`.
70 lines
1.9 KiB
Rust
70 lines
1.9 KiB
Rust
use codex_otel::MetricsClient;
|
|
|
|
use crate::MEMORY_TOOLS_NAMESPACE;
|
|
|
|
pub(crate) const MEMORIES_TOOL_CALL_METRIC: &str = "codex.memories.tool.call";
|
|
|
|
pub(crate) fn record_tool_call(
|
|
metrics_client: Option<&MetricsClient>,
|
|
operation: &str,
|
|
scope: &str,
|
|
success: bool,
|
|
truncated: &str,
|
|
) {
|
|
let Some(metrics_client) = metrics_client else {
|
|
return;
|
|
};
|
|
|
|
let tool = format!("{MEMORY_TOOLS_NAMESPACE}/{operation}");
|
|
let _ = metrics_client.counter(
|
|
MEMORIES_TOOL_CALL_METRIC,
|
|
/*inc*/ 1,
|
|
&[
|
|
("tool", tool.as_str()),
|
|
("operation", operation),
|
|
("scope", scope),
|
|
("status", status_tag(success)),
|
|
("truncated", truncated),
|
|
],
|
|
);
|
|
}
|
|
|
|
pub(crate) fn scope_from_path(path: &str) -> &'static str {
|
|
let path = path.trim_matches('/');
|
|
let path = path.strip_prefix("./").unwrap_or(path);
|
|
|
|
if path.is_empty() {
|
|
"root"
|
|
} else if path == "MEMORY.md" {
|
|
"memory_md"
|
|
} else if path == "memory_summary.md" {
|
|
"memory_summary"
|
|
} else if path == "raw_memories.md" {
|
|
"raw_memories"
|
|
} else if path == "rollout_summaries" || path.starts_with("rollout_summaries/") {
|
|
"rollout_summaries"
|
|
} else if path == "skills" || path.starts_with("skills/") {
|
|
"skills"
|
|
} else if path == "extensions/ad_hoc/notes" || path.starts_with("extensions/ad_hoc/notes/") {
|
|
"ad_hoc_notes"
|
|
} else {
|
|
"other"
|
|
}
|
|
}
|
|
|
|
pub(crate) fn scope_from_optional_path(path: Option<&str>, default: &'static str) -> &'static str {
|
|
path.map_or(default, scope_from_path)
|
|
}
|
|
|
|
pub(crate) fn truncated_tag(truncated: Option<bool>) -> &'static str {
|
|
match truncated {
|
|
Some(true) => "true",
|
|
Some(false) => "false",
|
|
None => "unknown",
|
|
}
|
|
}
|
|
|
|
fn status_tag(success: bool) -> &'static str {
|
|
if success { "succeeded" } else { "failed" }
|
|
}
|