feat: add opt-in early tool call dispatch
This commit is contained in:
@@ -542,6 +542,8 @@ pub struct EngineManifestConfig {
|
||||
#[serde(default)]
|
||||
pub reasoning: Option<ReasoningControl>,
|
||||
#[serde(default)]
|
||||
pub tool_call_dispatch: Option<crate::ToolCallDispatchMode>,
|
||||
#[serde(default)]
|
||||
pub tool_output: ToolOutputLimitsPartial,
|
||||
#[serde(default)]
|
||||
pub file_upload: FileUploadLimitsPartial,
|
||||
@@ -868,6 +870,7 @@ impl EngineManifestConfig {
|
||||
top_k: upper.top_k.or(self.top_k),
|
||||
stop_sequences: upper.stop_sequences.or(self.stop_sequences),
|
||||
reasoning: upper.reasoning.or(self.reasoning),
|
||||
tool_call_dispatch: upper.tool_call_dispatch.or(self.tool_call_dispatch),
|
||||
tool_output: self.tool_output.merge(upper.tool_output),
|
||||
file_upload: self.file_upload.merge(upper.file_upload),
|
||||
}
|
||||
@@ -1171,6 +1174,7 @@ impl TryFrom<WorkerManifestConfig> for WorkerManifest {
|
||||
top_k: cfg.engine.top_k,
|
||||
stop_sequences: cfg.engine.stop_sequences.unwrap_or_default(),
|
||||
reasoning: cfg.engine.reasoning,
|
||||
tool_call_dispatch: cfg.engine.tool_call_dispatch.unwrap_or_default(),
|
||||
tool_output: ToolOutputLimits {
|
||||
default_max_bytes: cfg
|
||||
.engine
|
||||
@@ -1343,6 +1347,39 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tool_call_dispatch_defaults_merges_and_round_trips() {
|
||||
let manifest: WorkerManifest = minimal_valid().try_into().unwrap();
|
||||
assert_eq!(
|
||||
manifest.engine.tool_call_dispatch,
|
||||
crate::ToolCallDispatchMode::AfterResponse
|
||||
);
|
||||
|
||||
let lower = WorkerManifestConfig {
|
||||
engine: EngineManifestConfig {
|
||||
tool_call_dispatch: Some(crate::ToolCallDispatchMode::OnToolCallComplete),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
let upper = WorkerManifestConfig::default();
|
||||
assert_eq!(
|
||||
lower.merge(upper).engine.tool_call_dispatch,
|
||||
Some(crate::ToolCallDispatchMode::OnToolCallComplete)
|
||||
);
|
||||
|
||||
let mut configured = minimal_valid();
|
||||
configured.engine.tool_call_dispatch =
|
||||
Some(crate::ToolCallDispatchMode::OnToolCallComplete);
|
||||
let manifest: WorkerManifest = configured.try_into().unwrap();
|
||||
let snapshot = serde_json::to_value(&manifest).unwrap();
|
||||
let restored: WorkerManifest = serde_json::from_value(snapshot).unwrap();
|
||||
assert_eq!(
|
||||
restored.engine.tool_call_dispatch,
|
||||
crate::ToolCallDispatchMode::OnToolCallComplete
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_minimal_succeeds() {
|
||||
let manifest: WorkerManifest = minimal_valid().try_into().unwrap();
|
||||
|
||||
@@ -587,6 +587,20 @@ pub struct WorkerMeta {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
/// When the engine may begin executing provider-confirmed tool calls.
|
||||
///
|
||||
/// `OnToolCallComplete` advances only the start time: calls may still overlap,
|
||||
/// so completion order and externally allocated identifiers are not ordered.
|
||||
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ToolCallDispatchMode {
|
||||
/// Preserve the historical behavior: wait for the whole response stream.
|
||||
#[default]
|
||||
AfterResponse,
|
||||
/// Start each call once the provider emits a trustworthy per-call completion.
|
||||
OnToolCallComplete,
|
||||
}
|
||||
|
||||
/// Worker-level configuration embedded in the manifest.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EngineManifest {
|
||||
@@ -614,6 +628,9 @@ pub struct EngineManifest {
|
||||
pub stop_sequences: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub reasoning: Option<ReasoningControl>,
|
||||
/// Tool-call start timing. Omitted manifests preserve `after_response`.
|
||||
#[serde(default)]
|
||||
pub tool_call_dispatch: ToolCallDispatchMode,
|
||||
/// Byte-size caps applied to tool `content` before it reaches the
|
||||
/// conversation history. The section is optional in TOML — when
|
||||
/// omitted, `ToolOutputLimits::default()` (64 KiB default cap, no
|
||||
|
||||
Reference in New Issue
Block a user