Expose invocation sources to extension tools (#40382)

## What changed

- Add `ToolCallSource` to extension `ToolCall`s and propagate direct or Code Mode
  invocation metadata, including the runtime cell and nested tool-call IDs.
- Add `ToolCall::response_byte_budget` so extension tools can bound direct-call
  responses by the host truncation policy while allowing Code Mode responses up
  to the tool's own limit.
- Share the skills extension's response-size limit between its `list` and `read`
  tools.

## Testing

- Verify that Code Mode source metadata is preserved when core constructs an
  extension tool call.

GitOrigin-RevId: b10aef01be30d35b67bee3af24a1a4175c9ee112
This commit is contained in:
Tamir Duberstein authored and copyberry committed 2026-08-24 11:02:14 +00:00
1 parent 6771ae7ac3
commit e3609f2d02
14 files changed
+70 -24

No files matched your search

+3 -3
View File
@@ -15,6 +15,7 @@ use crate::render::truncate_utf8_to_bytes;
use crate::warnings::bounded_warnings;
use super::MAX_HANDLE_BYTES;
use super::MAX_SKILL_RESPONSE_BYTES;
use super::SkillToolAuthority;
use super::SkillToolAuthoritySelector;
use super::SkillToolContext;
@@ -29,7 +30,6 @@ use super::skill_tool_name;
const TOOL_NAME: &str = "list";
const MAX_SKILLS_PER_PAGE: usize = 20;
const MAX_LIST_RESPONSE_BYTES: usize = 512 * 1024;
const OVERSIZED_ENTRY_WARNING: &str =
"Some skills were omitted because their metadata is too large.";
@@ -114,7 +114,7 @@ impl ToolExecutor<ToolCall> for ListTool {
warnings: warnings.clone(),
next_cursor: (end < skills.len()).then(|| pagination_cursor(&skills, end)),
};
if serialized_len(&response)? <= MAX_LIST_RESPONSE_BYTES {
if serialized_len(&response)? <= MAX_SKILL_RESPONSE_BYTES {
return skill_json_output(&response, args.authority);
}
if end.saturating_sub(start) > 1 {
@@ -137,7 +137,7 @@ fn single_entry_response_is_bounded(skill: &ListedSkill) -> bool {
warnings: Vec::new(),
next_cursor: Some(pagination_cursor(skill, usize::MAX)),
})
.is_ok_and(|size| size <= MAX_LIST_RESPONSE_BYTES)
.is_ok_and(|size| size <= MAX_SKILL_RESPONSE_BYTES)
}
fn listed_skill(entry: SkillCatalogEntry) -> Option<ListedSkill> {
+1
View File
@@ -50,6 +50,7 @@ mod schema;
const SKILLS_NAMESPACE: &str = "skills";
const MAX_HANDLE_BYTES: usize = 2_048;
const MAX_SKILL_RESPONSE_BYTES: usize = 512 * 1024;
pub(crate) fn skill_tools(
providers: SkillProviders,
+3 -3
View File
@@ -14,6 +14,7 @@ use crate::provider::SkillReadRequest;
use crate::render::build_alias_plan;
use super::MAX_HANDLE_BYTES;
use super::MAX_SKILL_RESPONSE_BYTES;
use super::SkillToolAuthority;
use super::SkillToolContext;
use super::pagination_cursor;
@@ -26,7 +27,6 @@ use super::skill_tool_name;
use super::validate_handle;
const TOOL_NAME: &str = "read";
const MAX_READ_RESPONSE_BYTES: usize = 512 * 1024;
#[derive(Deserialize, JsonSchema)]
struct ReadArgs {
@@ -237,7 +237,7 @@ fn page_response(
next_cursor,
};
let complete = response(contents.len(), None);
if serialized_len(&complete)? <= MAX_READ_RESPONSE_BYTES {
if serialized_len(&complete)? <= MAX_SKILL_RESPONSE_BYTES {
return Ok(complete);
}
@@ -248,7 +248,7 @@ fn page_response(
end -= 1;
}
let candidate = response(end, Some(pagination_cursor(contents, end)));
if serialized_len(&candidate)? <= MAX_READ_RESPONSE_BYTES {
if serialized_len(&candidate)? <= MAX_SKILL_RESPONSE_BYTES {
return Ok(candidate);
}
}
@@ -24,6 +24,7 @@ use codex_extension_api::SkillInvocationInput;
use codex_extension_api::SkillInvocationKind;
use codex_extension_api::ThreadStartInput;
use codex_extension_api::ToolCall;
use codex_extension_api::ToolCallSource;
use codex_extension_api::ToolPayload;
use codex_extension_api::TurnInputContext;
use codex_extension_api::WorldStateContributionInput;
@@ -1604,6 +1605,7 @@ async fn skills_list_only_returns_model_visible_bounded_metadata() -> TestResult
model: "gpt-test".to_string(),
codex_turn_metadata: None,
truncation_policy: TruncationPolicy::Bytes(1_024),
source: ToolCallSource::Direct,
conversation_history: ConversationHistory::default(),
turn_item_emitter: Arc::new(NoopTurnItemEmitter),
environments: Vec::new(),