mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-10 11:19:50 +08:00
refactor: 移除 Python 后端源码,全面迁移至 Rust gateway 架构
- 删除全部 Python 源码 (src/) 及 Alembic 迁移脚本,归档至 _deprecated_py_src/ - 重构 Rust gateway ai_pipeline: 拆分 planner/finalize 模块,新增 contracts/adaptation 层 - 重组 handlers 模块为 admin/public/proxy/internal/shared 子模块结构 - 新增 executor 模块,引入 Rust 原生数据库迁移 (aether-data/migrations) - 简化 CI/Docker 构建流程,移除 base image 二级构建,统一为单一 app image - 移除 Python 相关基础设施文件 (entrypoint.sh, gunicorn_conf.py, Dockerfile.base)
This commit is contained in:
+4
-4
@@ -64,13 +64,13 @@ enum FrameParseError {
|
||||
Invalid(String),
|
||||
}
|
||||
|
||||
#[path = "stream/decoder.rs"]
|
||||
#[path = "kiro_stream/stream/decoder.rs"]
|
||||
mod decoder;
|
||||
#[path = "stream/state.rs"]
|
||||
#[path = "kiro_stream/stream/state.rs"]
|
||||
mod state;
|
||||
#[path = "stream/util.rs"]
|
||||
#[path = "kiro_stream/stream/util.rs"]
|
||||
mod util;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "stream/tests.rs"]
|
||||
#[path = "kiro_stream/stream/tests.rs"]
|
||||
mod tests;
|
||||
@@ -0,0 +1,18 @@
|
||||
pub(crate) mod kiro_stream;
|
||||
pub(crate) mod private_envelope;
|
||||
pub(crate) mod surfaces;
|
||||
|
||||
pub(crate) use kiro_stream::KiroToClaudeCliStreamState;
|
||||
pub(crate) use private_envelope::{
|
||||
maybe_build_provider_private_stream_normalizer,
|
||||
maybe_normalize_provider_private_sync_report_payload,
|
||||
normalize_provider_private_report_context, normalize_provider_private_response_value,
|
||||
provider_private_response_allows_sync_finalize, transform_provider_private_stream_line,
|
||||
};
|
||||
pub(crate) use surfaces::{
|
||||
provider_adaptation_allows_sync_finalize_envelope, provider_adaptation_anchor_api_format,
|
||||
provider_adaptation_descriptor_for_envelope, provider_adaptation_descriptor_for_provider_type,
|
||||
provider_adaptation_requires_eventstream_accept,
|
||||
provider_adaptation_should_unwrap_stream_envelope, ANTIGRAVITY_V1INTERNAL_ENVELOPE_NAME,
|
||||
GEMINI_CLI_V1INTERNAL_ENVELOPE_NAME,
|
||||
};
|
||||
+1
-1
@@ -3,7 +3,7 @@ use std::collections::BTreeMap;
|
||||
use base64::Engine as _;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::gateway::ai_pipeline::private_surfaces::{
|
||||
use crate::gateway::ai_pipeline::adaptation::surfaces::{
|
||||
provider_adaptation_allows_sync_finalize_envelope, provider_adaptation_descriptor_for_envelope,
|
||||
provider_adaptation_should_unwrap_stream_envelope, ANTIGRAVITY_V1INTERNAL_ENVELOPE_NAME,
|
||||
GEMINI_CLI_V1INTERNAL_ENVELOPE_NAME,
|
||||
@@ -0,0 +1,5 @@
|
||||
pub(crate) const EXECUTION_RUNTIME_SYNC_ACTION: &str = "execution_runtime_sync";
|
||||
pub(crate) const EXECUTION_RUNTIME_SYNC_DECISION_ACTION: &str = "execution_runtime_sync_decision";
|
||||
pub(crate) const EXECUTION_RUNTIME_STREAM_ACTION: &str = "execution_runtime_stream";
|
||||
pub(crate) const EXECUTION_RUNTIME_STREAM_DECISION_ACTION: &str =
|
||||
"execution_runtime_stream_decision";
|
||||
@@ -0,0 +1,43 @@
|
||||
pub(crate) mod actions;
|
||||
pub(crate) mod control_payloads;
|
||||
pub(crate) mod plan_kinds;
|
||||
pub(crate) mod report_kinds;
|
||||
|
||||
pub(crate) use actions::{
|
||||
EXECUTION_RUNTIME_STREAM_ACTION, EXECUTION_RUNTIME_STREAM_DECISION_ACTION,
|
||||
EXECUTION_RUNTIME_SYNC_ACTION, EXECUTION_RUNTIME_SYNC_DECISION_ACTION,
|
||||
};
|
||||
pub(crate) use control_payloads::{
|
||||
build_gateway_plan_request, generic_decision_missing_exact_provider_request,
|
||||
GatewayControlPlanRequest, GatewayControlPlanResponse, GatewayControlSyncDecisionResponse,
|
||||
};
|
||||
pub(crate) use plan_kinds::{
|
||||
CLAUDE_CHAT_STREAM_PLAN_KIND, CLAUDE_CHAT_SYNC_PLAN_KIND, CLAUDE_CLI_STREAM_PLAN_KIND,
|
||||
CLAUDE_CLI_SYNC_PLAN_KIND, GEMINI_CHAT_STREAM_PLAN_KIND, GEMINI_CHAT_SYNC_PLAN_KIND,
|
||||
GEMINI_CLI_STREAM_PLAN_KIND, GEMINI_CLI_SYNC_PLAN_KIND, GEMINI_FILES_DELETE_PLAN_KIND,
|
||||
GEMINI_FILES_DOWNLOAD_PLAN_KIND, GEMINI_FILES_GET_PLAN_KIND, GEMINI_FILES_LIST_PLAN_KIND,
|
||||
GEMINI_FILES_UPLOAD_PLAN_KIND, GEMINI_VIDEO_CANCEL_SYNC_PLAN_KIND,
|
||||
GEMINI_VIDEO_CREATE_SYNC_PLAN_KIND, OPENAI_CHAT_STREAM_PLAN_KIND, OPENAI_CHAT_SYNC_PLAN_KIND,
|
||||
OPENAI_CLI_STREAM_PLAN_KIND, OPENAI_CLI_SYNC_PLAN_KIND, OPENAI_COMPACT_STREAM_PLAN_KIND,
|
||||
OPENAI_COMPACT_SYNC_PLAN_KIND, OPENAI_VIDEO_CANCEL_SYNC_PLAN_KIND,
|
||||
OPENAI_VIDEO_CONTENT_PLAN_KIND, OPENAI_VIDEO_CREATE_SYNC_PLAN_KIND,
|
||||
OPENAI_VIDEO_DELETE_SYNC_PLAN_KIND, OPENAI_VIDEO_REMIX_SYNC_PLAN_KIND,
|
||||
};
|
||||
pub(crate) use report_kinds::{
|
||||
core_error_background_report_kind, core_error_default_client_api_format,
|
||||
core_success_background_report_kind, implicit_sync_finalize_report_kind,
|
||||
CLAUDE_CHAT_STREAM_SUCCESS_REPORT_KIND, CLAUDE_CHAT_SYNC_ERROR_REPORT_KIND,
|
||||
CLAUDE_CHAT_SYNC_FINALIZE_REPORT_KIND, CLAUDE_CHAT_SYNC_SUCCESS_REPORT_KIND,
|
||||
CLAUDE_CLI_STREAM_SUCCESS_REPORT_KIND, CLAUDE_CLI_SYNC_ERROR_REPORT_KIND,
|
||||
CLAUDE_CLI_SYNC_FINALIZE_REPORT_KIND, CLAUDE_CLI_SYNC_SUCCESS_REPORT_KIND,
|
||||
GEMINI_CHAT_STREAM_SUCCESS_REPORT_KIND, GEMINI_CHAT_SYNC_ERROR_REPORT_KIND,
|
||||
GEMINI_CHAT_SYNC_FINALIZE_REPORT_KIND, GEMINI_CHAT_SYNC_SUCCESS_REPORT_KIND,
|
||||
GEMINI_CLI_STREAM_SUCCESS_REPORT_KIND, GEMINI_CLI_SYNC_ERROR_REPORT_KIND,
|
||||
GEMINI_CLI_SYNC_FINALIZE_REPORT_KIND, GEMINI_CLI_SYNC_SUCCESS_REPORT_KIND,
|
||||
GEMINI_VIDEO_CREATE_SYNC_FINALIZE_REPORT_KIND, OPENAI_CHAT_STREAM_SUCCESS_REPORT_KIND,
|
||||
OPENAI_CHAT_SYNC_ERROR_REPORT_KIND, OPENAI_CHAT_SYNC_FINALIZE_REPORT_KIND,
|
||||
OPENAI_CHAT_SYNC_SUCCESS_REPORT_KIND, OPENAI_CLI_STREAM_SUCCESS_REPORT_KIND,
|
||||
OPENAI_CLI_SYNC_ERROR_REPORT_KIND, OPENAI_CLI_SYNC_FINALIZE_REPORT_KIND,
|
||||
OPENAI_CLI_SYNC_SUCCESS_REPORT_KIND, OPENAI_COMPACT_SYNC_ERROR_REPORT_KIND,
|
||||
OPENAI_COMPACT_SYNC_FINALIZE_REPORT_KIND, OPENAI_VIDEO_CREATE_SYNC_FINALIZE_REPORT_KIND,
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
pub(crate) const GEMINI_FILES_GET_PLAN_KIND: &str = "gemini_files_get";
|
||||
pub(crate) const GEMINI_FILES_UPLOAD_PLAN_KIND: &str = "gemini_files_upload";
|
||||
pub(crate) const GEMINI_FILES_LIST_PLAN_KIND: &str = "gemini_files_list";
|
||||
pub(crate) const GEMINI_FILES_DELETE_PLAN_KIND: &str = "gemini_files_delete";
|
||||
pub(crate) const GEMINI_FILES_DOWNLOAD_PLAN_KIND: &str = "gemini_files_download";
|
||||
pub(crate) const OPENAI_VIDEO_CONTENT_PLAN_KIND: &str = "openai_video_content";
|
||||
pub(crate) const OPENAI_VIDEO_CANCEL_SYNC_PLAN_KIND: &str = "openai_video_cancel_sync";
|
||||
pub(crate) const OPENAI_VIDEO_REMIX_SYNC_PLAN_KIND: &str = "openai_video_remix_sync";
|
||||
pub(crate) const OPENAI_VIDEO_DELETE_SYNC_PLAN_KIND: &str = "openai_video_delete_sync";
|
||||
pub(crate) const GEMINI_VIDEO_CREATE_SYNC_PLAN_KIND: &str = "gemini_video_create_sync";
|
||||
pub(crate) const GEMINI_VIDEO_CANCEL_SYNC_PLAN_KIND: &str = "gemini_video_cancel_sync";
|
||||
pub(crate) const OPENAI_CHAT_STREAM_PLAN_KIND: &str = "openai_chat_stream";
|
||||
pub(crate) const CLAUDE_CHAT_STREAM_PLAN_KIND: &str = "claude_chat_stream";
|
||||
pub(crate) const GEMINI_CHAT_STREAM_PLAN_KIND: &str = "gemini_chat_stream";
|
||||
pub(crate) const OPENAI_CLI_STREAM_PLAN_KIND: &str = "openai_cli_stream";
|
||||
pub(crate) const OPENAI_COMPACT_STREAM_PLAN_KIND: &str = "openai_compact_stream";
|
||||
pub(crate) const CLAUDE_CLI_STREAM_PLAN_KIND: &str = "claude_cli_stream";
|
||||
pub(crate) const GEMINI_CLI_STREAM_PLAN_KIND: &str = "gemini_cli_stream";
|
||||
pub(crate) const OPENAI_VIDEO_CREATE_SYNC_PLAN_KIND: &str = "openai_video_create_sync";
|
||||
pub(crate) const OPENAI_CHAT_SYNC_PLAN_KIND: &str = "openai_chat_sync";
|
||||
pub(crate) const OPENAI_CLI_SYNC_PLAN_KIND: &str = "openai_cli_sync";
|
||||
pub(crate) const OPENAI_COMPACT_SYNC_PLAN_KIND: &str = "openai_compact_sync";
|
||||
pub(crate) const CLAUDE_CHAT_SYNC_PLAN_KIND: &str = "claude_chat_sync";
|
||||
pub(crate) const GEMINI_CHAT_SYNC_PLAN_KIND: &str = "gemini_chat_sync";
|
||||
pub(crate) const CLAUDE_CLI_SYNC_PLAN_KIND: &str = "claude_cli_sync";
|
||||
pub(crate) const GEMINI_CLI_SYNC_PLAN_KIND: &str = "gemini_cli_sync";
|
||||
@@ -0,0 +1,92 @@
|
||||
use super::plan_kinds::{
|
||||
CLAUDE_CHAT_SYNC_PLAN_KIND, CLAUDE_CLI_SYNC_PLAN_KIND, GEMINI_CHAT_SYNC_PLAN_KIND,
|
||||
GEMINI_CLI_SYNC_PLAN_KIND, OPENAI_CHAT_SYNC_PLAN_KIND, OPENAI_CLI_SYNC_PLAN_KIND,
|
||||
OPENAI_COMPACT_SYNC_PLAN_KIND,
|
||||
};
|
||||
|
||||
pub(crate) const OPENAI_CHAT_SYNC_FINALIZE_REPORT_KIND: &str = "openai_chat_sync_finalize";
|
||||
pub(crate) const CLAUDE_CHAT_SYNC_FINALIZE_REPORT_KIND: &str = "claude_chat_sync_finalize";
|
||||
pub(crate) const GEMINI_CHAT_SYNC_FINALIZE_REPORT_KIND: &str = "gemini_chat_sync_finalize";
|
||||
pub(crate) const OPENAI_CLI_SYNC_FINALIZE_REPORT_KIND: &str = "openai_cli_sync_finalize";
|
||||
pub(crate) const OPENAI_COMPACT_SYNC_FINALIZE_REPORT_KIND: &str = "openai_compact_sync_finalize";
|
||||
pub(crate) const CLAUDE_CLI_SYNC_FINALIZE_REPORT_KIND: &str = "claude_cli_sync_finalize";
|
||||
pub(crate) const GEMINI_CLI_SYNC_FINALIZE_REPORT_KIND: &str = "gemini_cli_sync_finalize";
|
||||
pub(crate) const OPENAI_VIDEO_CREATE_SYNC_FINALIZE_REPORT_KIND: &str =
|
||||
"openai_video_create_sync_finalize";
|
||||
pub(crate) const GEMINI_VIDEO_CREATE_SYNC_FINALIZE_REPORT_KIND: &str =
|
||||
"gemini_video_create_sync_finalize";
|
||||
|
||||
pub(crate) const OPENAI_CHAT_SYNC_SUCCESS_REPORT_KIND: &str = "openai_chat_sync_success";
|
||||
pub(crate) const CLAUDE_CHAT_SYNC_SUCCESS_REPORT_KIND: &str = "claude_chat_sync_success";
|
||||
pub(crate) const GEMINI_CHAT_SYNC_SUCCESS_REPORT_KIND: &str = "gemini_chat_sync_success";
|
||||
pub(crate) const OPENAI_CLI_SYNC_SUCCESS_REPORT_KIND: &str = "openai_cli_sync_success";
|
||||
pub(crate) const CLAUDE_CLI_SYNC_SUCCESS_REPORT_KIND: &str = "claude_cli_sync_success";
|
||||
pub(crate) const GEMINI_CLI_SYNC_SUCCESS_REPORT_KIND: &str = "gemini_cli_sync_success";
|
||||
|
||||
pub(crate) const OPENAI_CHAT_STREAM_SUCCESS_REPORT_KIND: &str = "openai_chat_stream_success";
|
||||
pub(crate) const CLAUDE_CHAT_STREAM_SUCCESS_REPORT_KIND: &str = "claude_chat_stream_success";
|
||||
pub(crate) const GEMINI_CHAT_STREAM_SUCCESS_REPORT_KIND: &str = "gemini_chat_stream_success";
|
||||
pub(crate) const OPENAI_CLI_STREAM_SUCCESS_REPORT_KIND: &str = "openai_cli_stream_success";
|
||||
pub(crate) const CLAUDE_CLI_STREAM_SUCCESS_REPORT_KIND: &str = "claude_cli_stream_success";
|
||||
pub(crate) const GEMINI_CLI_STREAM_SUCCESS_REPORT_KIND: &str = "gemini_cli_stream_success";
|
||||
|
||||
pub(crate) const OPENAI_CHAT_SYNC_ERROR_REPORT_KIND: &str = "openai_chat_sync_error";
|
||||
pub(crate) const CLAUDE_CHAT_SYNC_ERROR_REPORT_KIND: &str = "claude_chat_sync_error";
|
||||
pub(crate) const GEMINI_CHAT_SYNC_ERROR_REPORT_KIND: &str = "gemini_chat_sync_error";
|
||||
pub(crate) const OPENAI_CLI_SYNC_ERROR_REPORT_KIND: &str = "openai_cli_sync_error";
|
||||
pub(crate) const OPENAI_COMPACT_SYNC_ERROR_REPORT_KIND: &str = "openai_compact_sync_error";
|
||||
pub(crate) const CLAUDE_CLI_SYNC_ERROR_REPORT_KIND: &str = "claude_cli_sync_error";
|
||||
pub(crate) const GEMINI_CLI_SYNC_ERROR_REPORT_KIND: &str = "gemini_cli_sync_error";
|
||||
|
||||
pub(crate) fn implicit_sync_finalize_report_kind(plan_kind: &str) -> Option<&'static str> {
|
||||
match plan_kind {
|
||||
OPENAI_CHAT_SYNC_PLAN_KIND => Some(OPENAI_CHAT_SYNC_FINALIZE_REPORT_KIND),
|
||||
CLAUDE_CHAT_SYNC_PLAN_KIND => Some(CLAUDE_CHAT_SYNC_FINALIZE_REPORT_KIND),
|
||||
GEMINI_CHAT_SYNC_PLAN_KIND => Some(GEMINI_CHAT_SYNC_FINALIZE_REPORT_KIND),
|
||||
OPENAI_CLI_SYNC_PLAN_KIND => Some(OPENAI_CLI_SYNC_FINALIZE_REPORT_KIND),
|
||||
OPENAI_COMPACT_SYNC_PLAN_KIND => Some(OPENAI_COMPACT_SYNC_FINALIZE_REPORT_KIND),
|
||||
CLAUDE_CLI_SYNC_PLAN_KIND => Some(CLAUDE_CLI_SYNC_FINALIZE_REPORT_KIND),
|
||||
GEMINI_CLI_SYNC_PLAN_KIND => Some(GEMINI_CLI_SYNC_FINALIZE_REPORT_KIND),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn core_error_default_client_api_format(report_kind: &str) -> Option<&'static str> {
|
||||
match report_kind {
|
||||
OPENAI_CHAT_SYNC_FINALIZE_REPORT_KIND => Some("openai:chat"),
|
||||
CLAUDE_CHAT_SYNC_FINALIZE_REPORT_KIND => Some("claude:chat"),
|
||||
GEMINI_CHAT_SYNC_FINALIZE_REPORT_KIND => Some("gemini:chat"),
|
||||
OPENAI_CLI_SYNC_FINALIZE_REPORT_KIND => Some("openai:cli"),
|
||||
OPENAI_COMPACT_SYNC_FINALIZE_REPORT_KIND => Some("openai:compact"),
|
||||
CLAUDE_CLI_SYNC_FINALIZE_REPORT_KIND => Some("claude:cli"),
|
||||
GEMINI_CLI_SYNC_FINALIZE_REPORT_KIND => Some("gemini:cli"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn core_error_background_report_kind(report_kind: &str) -> Option<&'static str> {
|
||||
match report_kind {
|
||||
OPENAI_CHAT_SYNC_FINALIZE_REPORT_KIND => Some(OPENAI_CHAT_SYNC_ERROR_REPORT_KIND),
|
||||
CLAUDE_CHAT_SYNC_FINALIZE_REPORT_KIND => Some(CLAUDE_CHAT_SYNC_ERROR_REPORT_KIND),
|
||||
GEMINI_CHAT_SYNC_FINALIZE_REPORT_KIND => Some(GEMINI_CHAT_SYNC_ERROR_REPORT_KIND),
|
||||
OPENAI_CLI_SYNC_FINALIZE_REPORT_KIND => Some(OPENAI_CLI_SYNC_ERROR_REPORT_KIND),
|
||||
OPENAI_COMPACT_SYNC_FINALIZE_REPORT_KIND => Some(OPENAI_COMPACT_SYNC_ERROR_REPORT_KIND),
|
||||
CLAUDE_CLI_SYNC_FINALIZE_REPORT_KIND => Some(CLAUDE_CLI_SYNC_ERROR_REPORT_KIND),
|
||||
GEMINI_CLI_SYNC_FINALIZE_REPORT_KIND => Some(GEMINI_CLI_SYNC_ERROR_REPORT_KIND),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn core_success_background_report_kind(report_kind: &str) -> Option<&'static str> {
|
||||
match report_kind {
|
||||
OPENAI_CHAT_SYNC_FINALIZE_REPORT_KIND => Some(OPENAI_CHAT_SYNC_SUCCESS_REPORT_KIND),
|
||||
CLAUDE_CHAT_SYNC_FINALIZE_REPORT_KIND => Some(CLAUDE_CHAT_SYNC_SUCCESS_REPORT_KIND),
|
||||
GEMINI_CHAT_SYNC_FINALIZE_REPORT_KIND => Some(GEMINI_CHAT_SYNC_SUCCESS_REPORT_KIND),
|
||||
OPENAI_CLI_SYNC_FINALIZE_REPORT_KIND | OPENAI_COMPACT_SYNC_FINALIZE_REPORT_KIND => {
|
||||
Some(OPENAI_CLI_SYNC_SUCCESS_REPORT_KIND)
|
||||
}
|
||||
CLAUDE_CLI_SYNC_FINALIZE_REPORT_KIND => Some(CLAUDE_CLI_SYNC_SUCCESS_REPORT_KIND),
|
||||
GEMINI_CLI_SYNC_FINALIZE_REPORT_KIND => Some(GEMINI_CLI_SYNC_SUCCESS_REPORT_KIND),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::gateway::ai_pipeline::contracts::core_success_background_report_kind as contract_core_success_background_report_kind;
|
||||
use crate::gateway::ai_pipeline::contracts::{
|
||||
core_error_background_report_kind as contract_core_error_background_report_kind,
|
||||
core_error_default_client_api_format as contract_core_error_default_client_api_format,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub(crate) enum LocalCoreSyncErrorKind {
|
||||
InvalidRequest,
|
||||
@@ -17,44 +24,16 @@ pub(crate) fn is_core_error_finalize_kind(report_kind: &str) -> bool {
|
||||
}
|
||||
|
||||
pub(crate) fn core_error_default_client_api_format(report_kind: &str) -> Option<&'static str> {
|
||||
match report_kind {
|
||||
"openai_chat_sync_finalize" => Some("openai:chat"),
|
||||
"claude_chat_sync_finalize" => Some("claude:chat"),
|
||||
"gemini_chat_sync_finalize" => Some("gemini:chat"),
|
||||
"openai_cli_sync_finalize" => Some("openai:cli"),
|
||||
"openai_compact_sync_finalize" => Some("openai:compact"),
|
||||
"claude_cli_sync_finalize" => Some("claude:cli"),
|
||||
"gemini_cli_sync_finalize" => Some("gemini:cli"),
|
||||
_ => None,
|
||||
}
|
||||
contract_core_error_default_client_api_format(report_kind)
|
||||
}
|
||||
|
||||
pub(crate) fn core_error_background_report_kind(report_kind: &str) -> Option<&'static str> {
|
||||
match report_kind {
|
||||
"openai_chat_sync_finalize" => Some("openai_chat_sync_error"),
|
||||
"claude_chat_sync_finalize" => Some("claude_chat_sync_error"),
|
||||
"gemini_chat_sync_finalize" => Some("gemini_chat_sync_error"),
|
||||
"openai_cli_sync_finalize" => Some("openai_cli_sync_error"),
|
||||
"openai_compact_sync_finalize" => Some("openai_compact_sync_error"),
|
||||
"claude_cli_sync_finalize" => Some("claude_cli_sync_error"),
|
||||
"gemini_cli_sync_finalize" => Some("gemini_cli_sync_error"),
|
||||
_ => None,
|
||||
}
|
||||
contract_core_error_background_report_kind(report_kind)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn core_success_background_report_kind(report_kind: &str) -> Option<&'static str> {
|
||||
match report_kind {
|
||||
"openai_chat_sync_finalize" => Some("openai_chat_sync_success"),
|
||||
"claude_chat_sync_finalize" => Some("claude_chat_sync_success"),
|
||||
"gemini_chat_sync_finalize" => Some("gemini_chat_sync_success"),
|
||||
"openai_cli_sync_finalize" | "openai_compact_sync_finalize" => {
|
||||
Some("openai_cli_sync_success")
|
||||
}
|
||||
"claude_cli_sync_finalize" => Some("claude_cli_sync_success"),
|
||||
"gemini_cli_sync_finalize" => Some("gemini_cli_sync_success"),
|
||||
_ => None,
|
||||
}
|
||||
contract_core_success_background_report_kind(report_kind)
|
||||
}
|
||||
|
||||
pub(crate) fn build_core_error_body_for_client_format(
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use serde_json::{json, Map, Value};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::shared::parse_openai_tool_arguments;
|
||||
use super::super::to_openai_chat::{extract_openai_text_content, parse_openai_tool_result_content};
|
||||
use super::shared::parse_openai_tool_arguments;
|
||||
use crate::gateway::ai_pipeline::planner::standard::{
|
||||
copy_request_number_field, map_openai_reasoning_effort_to_claude_output,
|
||||
parse_openai_stop_sequences, resolve_openai_chat_max_tokens,
|
||||
@@ -34,8 +34,10 @@ pub(crate) fn convert_openai_chat_request_to_claude_request(
|
||||
}
|
||||
}
|
||||
"user" => {
|
||||
let blocks =
|
||||
convert_openai_content_to_claude_blocks(message_object.get("content"), true)?;
|
||||
let blocks = convert_openai_content_to_claude_blocks(
|
||||
message_object.get("content"),
|
||||
true,
|
||||
)?;
|
||||
if !blocks.is_empty() {
|
||||
messages.push(build_claude_message("user", blocks));
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ use std::collections::BTreeMap;
|
||||
use serde_json::{json, Map, Value};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::shared::parse_openai_tool_arguments;
|
||||
use super::super::to_openai_chat::{extract_openai_text_content, parse_openai_tool_result_content};
|
||||
use super::shared::parse_openai_tool_arguments;
|
||||
use crate::gateway::ai_pipeline::planner::standard::{
|
||||
copy_request_number_field_as, map_openai_reasoning_effort_to_gemini_budget,
|
||||
parse_openai_stop_sequences, value_as_u64,
|
||||
@@ -37,8 +37,10 @@ pub(crate) fn convert_openai_chat_request_to_gemini_request(
|
||||
}
|
||||
}
|
||||
"user" => {
|
||||
let parts =
|
||||
convert_openai_content_to_gemini_parts(message_object.get("content"), true)?;
|
||||
let parts = convert_openai_content_to_gemini_parts(
|
||||
message_object.get("content"),
|
||||
true,
|
||||
)?;
|
||||
if !parts.is_empty() {
|
||||
contents.push(json!({
|
||||
"role": "user",
|
||||
|
||||
+1
-3
@@ -1,8 +1,6 @@
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use super::shared::{
|
||||
build_openai_cli_response, canonicalize_tool_arguments,
|
||||
};
|
||||
use super::shared::{build_openai_cli_response, canonicalize_tool_arguments};
|
||||
|
||||
pub(crate) fn convert_openai_chat_response_to_openai_cli(
|
||||
body_json: &Value,
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use super::shared::{build_generated_tool_call_id, canonicalize_tool_arguments};
|
||||
use super::super::from_openai_chat::build_openai_cli_response;
|
||||
use super::shared::{build_generated_tool_call_id, canonicalize_tool_arguments};
|
||||
|
||||
pub(crate) fn convert_claude_cli_response_to_openai_cli(
|
||||
body_json: &Value,
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use super::shared::{build_generated_tool_call_id, canonicalize_tool_arguments};
|
||||
use super::super::from_openai_chat::build_openai_cli_response;
|
||||
use super::shared::{build_generated_tool_call_id, canonicalize_tool_arguments};
|
||||
|
||||
pub(crate) fn convert_gemini_cli_response_to_openai_cli(
|
||||
body_json: &Value,
|
||||
|
||||
@@ -4,14 +4,13 @@ use axum::body::Body;
|
||||
use axum::http::Response;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::gateway::ai_pipeline::contracts::core_success_background_report_kind;
|
||||
pub(crate) use crate::gateway::ai_pipeline::runtime::{
|
||||
normalize_provider_private_response_value as unwrap_local_finalize_response_value,
|
||||
provider_private_response_allows_sync_finalize as local_finalize_allows_envelope,
|
||||
};
|
||||
use crate::gateway::{
|
||||
build_client_response_from_parts, GatewayControlDecision, GatewayError,
|
||||
GatewaySyncReportRequest,
|
||||
};
|
||||
use crate::gateway::api::response::build_client_response_from_parts;
|
||||
use crate::gateway::{GatewayControlDecision, GatewayError, GatewaySyncReportRequest};
|
||||
|
||||
pub(crate) struct LocalCoreSyncFinalizeOutcome {
|
||||
pub(crate) response: Response<Body>,
|
||||
@@ -127,17 +126,7 @@ fn map_local_finalize_to_success_report(
|
||||
}
|
||||
|
||||
fn map_local_finalize_kind_to_success_report_kind(report_kind: &str) -> Option<&'static str> {
|
||||
match report_kind {
|
||||
"openai_chat_sync_finalize" => Some("openai_chat_sync_success"),
|
||||
"claude_chat_sync_finalize" => Some("claude_chat_sync_success"),
|
||||
"gemini_chat_sync_finalize" => Some("gemini_chat_sync_success"),
|
||||
"openai_cli_sync_finalize" | "openai_compact_sync_finalize" => {
|
||||
Some("openai_cli_sync_success")
|
||||
}
|
||||
"claude_cli_sync_finalize" => Some("claude_cli_sync_success"),
|
||||
"gemini_cli_sync_finalize" => Some("gemini_cli_sync_success"),
|
||||
_ => None,
|
||||
}
|
||||
core_success_background_report_kind(report_kind)
|
||||
}
|
||||
|
||||
pub(crate) fn canonicalize_tool_arguments(value: Option<Value>) -> String {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::gateway::ai_pipeline::adaptation::private_envelope::transform_provider_private_stream_line as transform_envelope_line;
|
||||
use crate::gateway::ai_pipeline::finalize::sse::{encode_done_sse, encode_json_sse};
|
||||
use crate::gateway::ai_pipeline::finalize::standard::{
|
||||
BufferedCliConversionStreamState, BufferedStandardConversionStreamState,
|
||||
ClaudeToOpenAIChatStreamState, GeminiToOpenAIChatStreamState, OpenAICliToOpenAIChatStreamState,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::finalize::sse::{encode_done_sse, encode_json_sse};
|
||||
use crate::gateway::ai_pipeline::private_response::transform_provider_private_stream_line as transform_envelope_line;
|
||||
use crate::gateway::ai_pipeline::runtime::KiroToClaudeCliStreamState;
|
||||
use crate::gateway::GatewayError;
|
||||
|
||||
|
||||
@@ -8,10 +8,8 @@ use serde_json::{json, Map, Value};
|
||||
use crate::gateway::ai_pipeline::conversion::{
|
||||
sync_chat_response_conversion_kind, sync_cli_response_conversion_kind,
|
||||
};
|
||||
use crate::gateway::{
|
||||
build_client_response_from_parts, GatewayControlDecision, GatewayError,
|
||||
GatewaySyncReportRequest,
|
||||
};
|
||||
use crate::gateway::api::response::build_client_response_from_parts;
|
||||
use crate::gateway::{GatewayControlDecision, GatewayError, GatewaySyncReportRequest};
|
||||
|
||||
pub(crate) use crate::gateway::ai_pipeline::finalize::common::{
|
||||
build_generated_tool_call_id, build_local_success_outcome,
|
||||
@@ -47,7 +45,7 @@ pub(crate) fn maybe_build_local_core_sync_finalize_response(
|
||||
payload: &GatewaySyncReportRequest,
|
||||
) -> Result<Option<LocalCoreSyncFinalizeOutcome>, GatewayError> {
|
||||
let Some(normalized_payload) =
|
||||
crate::gateway::ai_pipeline::private_response::maybe_normalize_provider_private_sync_report_payload(payload)?
|
||||
crate::gateway::ai_pipeline::adaptation::private_envelope::maybe_normalize_provider_private_sync_report_payload(payload)?
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
pub(crate) mod common;
|
||||
pub(crate) mod sse;
|
||||
pub(crate) mod standard;
|
||||
pub(crate) use crate::gateway::api::response::{
|
||||
build_client_response, build_client_response_from_parts,
|
||||
};
|
||||
pub(crate) use crate::gateway::execution_runtime::maybe_build_local_sync_finalize_response;
|
||||
pub(crate) use common::build_local_success_outcome;
|
||||
pub(crate) use internal::{
|
||||
maybe_build_stream_response_rewriter, maybe_build_sync_finalize_outcome,
|
||||
maybe_compile_sync_finalize_response, LocalCoreSyncFinalizeOutcome,
|
||||
};
|
||||
pub(crate) use crate::gateway::build_client_response;
|
||||
pub(crate) use crate::gateway::build_client_response_from_parts;
|
||||
pub(crate) use crate::gateway::execution_runtime::maybe_build_local_sync_finalize_response;
|
||||
|
||||
pub(crate) mod internal;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::gateway::ai_pipeline::finalize::common::LocalCoreSyncFinalizeOutcome;
|
||||
use crate::gateway::{GatewayControlDecision, GatewayError, GatewaySyncReportRequest};
|
||||
|
||||
pub(crate) fn aggregate_claude_stream_sync_response(body: &[u8]) -> Option<Value> {
|
||||
super::claude_chat::aggregate_claude_stream_sync_response(body)
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_build_local_claude_stream_sync_response(
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
payload: &GatewaySyncReportRequest,
|
||||
) -> Result<Option<LocalCoreSyncFinalizeOutcome>, GatewayError> {
|
||||
super::claude_chat::maybe_build_local_claude_stream_sync_response(trace_id, decision, payload)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
use crate::gateway::ai_pipeline::finalize::common::LocalCoreSyncFinalizeOutcome;
|
||||
use crate::gateway::{GatewayControlDecision, GatewayError, GatewaySyncReportRequest};
|
||||
|
||||
pub(crate) fn maybe_build_local_claude_cli_stream_sync_response(
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
payload: &GatewaySyncReportRequest,
|
||||
) -> Result<Option<LocalCoreSyncFinalizeOutcome>, GatewayError> {
|
||||
super::claude_cli::maybe_build_local_claude_cli_stream_sync_response(
|
||||
trace_id, decision, payload,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::gateway::ai_pipeline::finalize::common::LocalCoreSyncFinalizeOutcome;
|
||||
use crate::gateway::{GatewayControlDecision, GatewayError, GatewaySyncReportRequest};
|
||||
|
||||
pub(crate) fn aggregate_gemini_stream_sync_response(body: &[u8]) -> Option<Value> {
|
||||
super::gemini_chat::aggregate_gemini_stream_sync_response(body)
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_build_local_gemini_stream_sync_response(
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
payload: &GatewaySyncReportRequest,
|
||||
) -> Result<Option<LocalCoreSyncFinalizeOutcome>, GatewayError> {
|
||||
super::gemini_chat::maybe_build_local_gemini_stream_sync_response(trace_id, decision, payload)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
use crate::gateway::ai_pipeline::finalize::common::LocalCoreSyncFinalizeOutcome;
|
||||
use crate::gateway::{GatewayControlDecision, GatewayError, GatewaySyncReportRequest};
|
||||
|
||||
pub(crate) fn maybe_build_local_gemini_cli_stream_sync_response(
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
payload: &GatewaySyncReportRequest,
|
||||
) -> Result<Option<LocalCoreSyncFinalizeOutcome>, GatewayError> {
|
||||
super::gemini_cli::maybe_build_local_gemini_cli_stream_sync_response(
|
||||
trace_id, decision, payload,
|
||||
)
|
||||
}
|
||||
@@ -9,12 +9,20 @@ use crate::gateway::{GatewayControlDecision, GatewayError, GatewaySyncReportRequ
|
||||
|
||||
#[path = "claude/chat.rs"]
|
||||
mod claude_chat;
|
||||
#[path = "claude/chat_stream.rs"]
|
||||
mod claude_chat_stream;
|
||||
#[path = "claude/cli.rs"]
|
||||
mod claude_cli;
|
||||
#[path = "claude/cli_stream.rs"]
|
||||
mod claude_cli_stream;
|
||||
#[path = "gemini/chat.rs"]
|
||||
mod gemini_chat;
|
||||
#[path = "gemini/chat_stream.rs"]
|
||||
mod gemini_chat_stream;
|
||||
#[path = "gemini/cli.rs"]
|
||||
mod gemini_cli;
|
||||
#[path = "gemini/cli_stream.rs"]
|
||||
mod gemini_cli_stream;
|
||||
#[path = "openai/chat.rs"]
|
||||
mod openai_chat;
|
||||
#[path = "openai/chat_stream.rs"]
|
||||
@@ -24,8 +32,8 @@ mod openai_cli;
|
||||
#[path = "openai/cli_stream.rs"]
|
||||
mod openai_cli_stream;
|
||||
|
||||
#[path = "stream.rs"]
|
||||
mod stream;
|
||||
#[path = "stream_common.rs"]
|
||||
mod stream_common;
|
||||
|
||||
pub(crate) use crate::gateway::ai_pipeline::conversion::response::{
|
||||
build_openai_cli_response, convert_claude_chat_response_to_openai_chat,
|
||||
@@ -34,18 +42,19 @@ pub(crate) use crate::gateway::ai_pipeline::conversion::response::{
|
||||
convert_openai_chat_response_to_gemini_chat, convert_openai_chat_response_to_openai_cli,
|
||||
convert_openai_cli_response_to_openai_chat,
|
||||
};
|
||||
pub(crate) use claude_chat::{
|
||||
pub(crate) use claude_chat::maybe_build_local_claude_sync_response;
|
||||
pub(crate) use claude_chat_stream::{
|
||||
aggregate_claude_stream_sync_response, maybe_build_local_claude_stream_sync_response,
|
||||
maybe_build_local_claude_sync_response,
|
||||
};
|
||||
pub(crate) use claude_cli::maybe_build_local_claude_cli_stream_sync_response;
|
||||
pub(crate) use gemini_chat::{
|
||||
pub(crate) use claude_cli_stream::maybe_build_local_claude_cli_stream_sync_response;
|
||||
pub(crate) use gemini_chat::maybe_build_local_gemini_sync_response;
|
||||
pub(crate) use gemini_chat_stream::{
|
||||
aggregate_gemini_stream_sync_response, maybe_build_local_gemini_stream_sync_response,
|
||||
maybe_build_local_gemini_sync_response,
|
||||
};
|
||||
pub(crate) use gemini_cli::maybe_build_local_gemini_cli_stream_sync_response;
|
||||
pub(crate) use gemini_cli_stream::maybe_build_local_gemini_cli_stream_sync_response;
|
||||
pub(crate) use openai_chat::{
|
||||
aggregate_openai_chat_stream_sync_response, maybe_build_local_openai_chat_cross_format_stream_sync_response,
|
||||
aggregate_openai_chat_stream_sync_response,
|
||||
maybe_build_local_openai_chat_cross_format_stream_sync_response,
|
||||
maybe_build_local_openai_chat_cross_format_sync_response,
|
||||
maybe_build_local_openai_chat_stream_sync_response,
|
||||
maybe_build_local_openai_chat_sync_response,
|
||||
@@ -54,12 +63,13 @@ pub(crate) use openai_chat_stream::{
|
||||
ClaudeToOpenAIChatStreamState, GeminiToOpenAIChatStreamState, OpenAICliToOpenAIChatStreamState,
|
||||
};
|
||||
pub(crate) use openai_cli::{
|
||||
aggregate_openai_cli_stream_sync_response, maybe_build_local_openai_cli_cross_format_stream_sync_response,
|
||||
aggregate_openai_cli_stream_sync_response,
|
||||
maybe_build_local_openai_cli_cross_format_stream_sync_response,
|
||||
maybe_build_local_openai_cli_cross_format_sync_response,
|
||||
maybe_build_local_openai_cli_stream_sync_response,
|
||||
};
|
||||
pub(crate) use openai_cli_stream::BufferedCliConversionStreamState;
|
||||
pub(crate) use stream::BufferedStandardConversionStreamState;
|
||||
pub(crate) use stream_common::BufferedStandardConversionStreamState;
|
||||
|
||||
pub(crate) fn aggregate_standard_chat_stream_sync_response(
|
||||
body: &[u8],
|
||||
|
||||
@@ -6,13 +6,13 @@ use super::{
|
||||
aggregate_openai_cli_stream_sync_response, convert_claude_chat_response_to_openai_chat,
|
||||
convert_gemini_chat_response_to_openai_chat,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::conversion::sync_chat_response_conversion_kind;
|
||||
use crate::gateway::ai_pipeline::finalize::common::{
|
||||
build_generated_tool_call_id, build_local_success_outcome,
|
||||
build_local_success_outcome_with_conversion_report, canonicalize_tool_arguments,
|
||||
local_finalize_allows_envelope, unwrap_local_finalize_response_value,
|
||||
LocalCoreSyncFinalizeOutcome,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::conversion::sync_chat_response_conversion_kind;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct OpenAIChatChoiceState {
|
||||
|
||||
@@ -5,12 +5,12 @@ use super::{
|
||||
aggregate_claude_stream_sync_response, aggregate_gemini_stream_sync_response,
|
||||
convert_claude_cli_response_to_openai_cli, convert_gemini_cli_response_to_openai_cli,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::conversion::sync_cli_response_conversion_kind;
|
||||
use crate::gateway::ai_pipeline::finalize::common::{
|
||||
build_local_success_outcome, build_local_success_outcome_with_conversion_report,
|
||||
canonicalize_tool_arguments, local_finalize_allows_envelope,
|
||||
unwrap_local_finalize_response_value, LocalCoreSyncFinalizeOutcome,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::conversion::sync_cli_response_conversion_kind;
|
||||
|
||||
pub(crate) fn maybe_build_local_openai_cli_stream_sync_response(
|
||||
trace_id: &str,
|
||||
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use crate::gateway::ai_pipeline::adaptation::private_envelope::transform_provider_private_stream_line as transform_envelope_line;
|
||||
use crate::gateway::ai_pipeline::adaptation::surfaces::provider_adaptation_should_unwrap_stream_envelope;
|
||||
use crate::gateway::ai_pipeline::finalize::sse::{encode_done_sse, encode_json_sse};
|
||||
use crate::gateway::ai_pipeline::finalize::standard::{
|
||||
aggregate_standard_chat_stream_sync_response, aggregate_standard_cli_stream_sync_response,
|
||||
convert_standard_chat_response, convert_standard_cli_response,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::finalize::sse::{encode_done_sse, encode_json_sse};
|
||||
use crate::gateway::ai_pipeline::private_response::transform_provider_private_stream_line as transform_envelope_line;
|
||||
use crate::gateway::ai_pipeline::private_surfaces::provider_adaptation_should_unwrap_stream_envelope;
|
||||
use crate::gateway::GatewayError;
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -1,6 +1,6 @@
|
||||
pub(crate) mod adaptation;
|
||||
pub(crate) mod contracts;
|
||||
pub(crate) mod conversion;
|
||||
pub(crate) mod finalize;
|
||||
pub(crate) mod planner;
|
||||
pub(crate) mod private_response;
|
||||
pub(crate) mod private_surfaces;
|
||||
pub(crate) mod runtime;
|
||||
|
||||
@@ -1,40 +1,22 @@
|
||||
use axum::body::Bytes;
|
||||
use base64::Engine as _;
|
||||
|
||||
pub(crate) use crate::gateway::ai_pipeline::contracts::{
|
||||
CLAUDE_CHAT_STREAM_PLAN_KIND, CLAUDE_CHAT_SYNC_PLAN_KIND, CLAUDE_CLI_STREAM_PLAN_KIND,
|
||||
CLAUDE_CLI_SYNC_PLAN_KIND, EXECUTION_RUNTIME_STREAM_ACTION,
|
||||
EXECUTION_RUNTIME_STREAM_DECISION_ACTION, EXECUTION_RUNTIME_SYNC_ACTION,
|
||||
EXECUTION_RUNTIME_SYNC_DECISION_ACTION, GEMINI_CHAT_STREAM_PLAN_KIND,
|
||||
GEMINI_CHAT_SYNC_PLAN_KIND, GEMINI_CLI_STREAM_PLAN_KIND, GEMINI_CLI_SYNC_PLAN_KIND,
|
||||
GEMINI_FILES_DELETE_PLAN_KIND, GEMINI_FILES_DOWNLOAD_PLAN_KIND, GEMINI_FILES_GET_PLAN_KIND,
|
||||
GEMINI_FILES_LIST_PLAN_KIND, GEMINI_FILES_UPLOAD_PLAN_KIND, GEMINI_VIDEO_CANCEL_SYNC_PLAN_KIND,
|
||||
GEMINI_VIDEO_CREATE_SYNC_PLAN_KIND, OPENAI_CHAT_STREAM_PLAN_KIND, OPENAI_CHAT_SYNC_PLAN_KIND,
|
||||
OPENAI_CLI_STREAM_PLAN_KIND, OPENAI_CLI_SYNC_PLAN_KIND, OPENAI_COMPACT_STREAM_PLAN_KIND,
|
||||
OPENAI_COMPACT_SYNC_PLAN_KIND, OPENAI_VIDEO_CANCEL_SYNC_PLAN_KIND,
|
||||
OPENAI_VIDEO_CONTENT_PLAN_KIND, OPENAI_VIDEO_CREATE_SYNC_PLAN_KIND,
|
||||
OPENAI_VIDEO_DELETE_SYNC_PLAN_KIND, OPENAI_VIDEO_REMIX_SYNC_PLAN_KIND,
|
||||
};
|
||||
use crate::gateway::headers::is_json_request;
|
||||
|
||||
pub(crate) const GEMINI_FILES_GET_PLAN_KIND: &str = "gemini_files_get";
|
||||
pub(crate) const GEMINI_FILES_UPLOAD_PLAN_KIND: &str = "gemini_files_upload";
|
||||
pub(crate) const GEMINI_FILES_LIST_PLAN_KIND: &str = "gemini_files_list";
|
||||
pub(crate) const GEMINI_FILES_DELETE_PLAN_KIND: &str = "gemini_files_delete";
|
||||
pub(crate) const GEMINI_FILES_DOWNLOAD_PLAN_KIND: &str = "gemini_files_download";
|
||||
pub(crate) const OPENAI_VIDEO_CONTENT_PLAN_KIND: &str = "openai_video_content";
|
||||
pub(crate) const OPENAI_VIDEO_CANCEL_SYNC_PLAN_KIND: &str = "openai_video_cancel_sync";
|
||||
pub(crate) const OPENAI_VIDEO_REMIX_SYNC_PLAN_KIND: &str = "openai_video_remix_sync";
|
||||
pub(crate) const OPENAI_VIDEO_DELETE_SYNC_PLAN_KIND: &str = "openai_video_delete_sync";
|
||||
pub(crate) const GEMINI_VIDEO_CREATE_SYNC_PLAN_KIND: &str = "gemini_video_create_sync";
|
||||
pub(crate) const GEMINI_VIDEO_CANCEL_SYNC_PLAN_KIND: &str = "gemini_video_cancel_sync";
|
||||
pub(crate) const OPENAI_CHAT_STREAM_PLAN_KIND: &str = "openai_chat_stream";
|
||||
pub(crate) const CLAUDE_CHAT_STREAM_PLAN_KIND: &str = "claude_chat_stream";
|
||||
pub(crate) const GEMINI_CHAT_STREAM_PLAN_KIND: &str = "gemini_chat_stream";
|
||||
pub(crate) const OPENAI_CLI_STREAM_PLAN_KIND: &str = "openai_cli_stream";
|
||||
pub(crate) const OPENAI_COMPACT_STREAM_PLAN_KIND: &str = "openai_compact_stream";
|
||||
pub(crate) const CLAUDE_CLI_STREAM_PLAN_KIND: &str = "claude_cli_stream";
|
||||
pub(crate) const GEMINI_CLI_STREAM_PLAN_KIND: &str = "gemini_cli_stream";
|
||||
pub(crate) const OPENAI_VIDEO_CREATE_SYNC_PLAN_KIND: &str = "openai_video_create_sync";
|
||||
pub(crate) const OPENAI_CHAT_SYNC_PLAN_KIND: &str = "openai_chat_sync";
|
||||
pub(crate) const OPENAI_CLI_SYNC_PLAN_KIND: &str = "openai_cli_sync";
|
||||
pub(crate) const OPENAI_COMPACT_SYNC_PLAN_KIND: &str = "openai_compact_sync";
|
||||
pub(crate) const CLAUDE_CHAT_SYNC_PLAN_KIND: &str = "claude_chat_sync";
|
||||
pub(crate) const GEMINI_CHAT_SYNC_PLAN_KIND: &str = "gemini_chat_sync";
|
||||
pub(crate) const CLAUDE_CLI_SYNC_PLAN_KIND: &str = "claude_cli_sync";
|
||||
pub(crate) const GEMINI_CLI_SYNC_PLAN_KIND: &str = "gemini_cli_sync";
|
||||
pub(crate) const EXECUTION_RUNTIME_SYNC_ACTION: &str = "execution_runtime_sync";
|
||||
pub(crate) const EXECUTION_RUNTIME_SYNC_DECISION_ACTION: &str = "execution_runtime_sync_decision";
|
||||
pub(crate) const EXECUTION_RUNTIME_STREAM_ACTION: &str = "execution_runtime_stream";
|
||||
pub(crate) const EXECUTION_RUNTIME_STREAM_DECISION_ACTION: &str =
|
||||
"execution_runtime_stream_decision";
|
||||
|
||||
pub(crate) fn parse_direct_request_body(
|
||||
parts: &http::request::Parts,
|
||||
body_bytes: &Bytes,
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
use axum::body::Body;
|
||||
use axum::http::Response;
|
||||
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::request_candidates::record_local_request_candidate_status;
|
||||
use crate::gateway::{
|
||||
execute_execution_runtime_stream, execute_execution_runtime_sync, AppState,
|
||||
GatewayControlDecision, GatewayError,
|
||||
};
|
||||
|
||||
pub(crate) trait LocalPlanAndReport {
|
||||
fn plan(&self) -> &aether_contracts::ExecutionPlan;
|
||||
|
||||
fn report_kind(&self) -> Option<String>;
|
||||
|
||||
fn report_context(&self) -> Option<serde_json::Value>;
|
||||
}
|
||||
|
||||
impl LocalPlanAndReport for LocalSyncPlanAndReport {
|
||||
fn plan(&self) -> &aether_contracts::ExecutionPlan {
|
||||
&self.plan
|
||||
}
|
||||
|
||||
fn report_kind(&self) -> Option<String> {
|
||||
self.report_kind.clone()
|
||||
}
|
||||
|
||||
fn report_context(&self) -> Option<serde_json::Value> {
|
||||
self.report_context.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalPlanAndReport for LocalStreamPlanAndReport {
|
||||
fn plan(&self) -> &aether_contracts::ExecutionPlan {
|
||||
&self.plan
|
||||
}
|
||||
|
||||
fn report_kind(&self) -> Option<String> {
|
||||
self.report_kind.clone()
|
||||
}
|
||||
|
||||
fn report_context(&self) -> Option<serde_json::Value> {
|
||||
self.report_context.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn execute_sync_plan_and_reports<T>(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
plan_kind: &str,
|
||||
plan_and_reports: Vec<T>,
|
||||
) -> Result<Option<Response<Body>>, GatewayError>
|
||||
where
|
||||
T: LocalPlanAndReport,
|
||||
{
|
||||
let mut remaining = plan_and_reports.into_iter();
|
||||
while let Some(plan_and_report) = remaining.next() {
|
||||
if let Some(response) = execute_execution_runtime_sync(
|
||||
state,
|
||||
parts.uri.path(),
|
||||
plan_and_report.plan().clone(),
|
||||
trace_id,
|
||||
decision,
|
||||
plan_kind,
|
||||
plan_and_report.report_kind(),
|
||||
plan_and_report.report_context(),
|
||||
)
|
||||
.await?
|
||||
{
|
||||
mark_unused_local_candidates(state, remaining.collect()).await;
|
||||
return Ok(Some(response));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub(crate) async fn execute_stream_plan_and_reports<T>(
|
||||
state: &AppState,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
plan_kind: &str,
|
||||
plan_and_reports: Vec<T>,
|
||||
) -> Result<Option<Response<Body>>, GatewayError>
|
||||
where
|
||||
T: LocalPlanAndReport,
|
||||
{
|
||||
let mut remaining = plan_and_reports.into_iter();
|
||||
while let Some(plan_and_report) = remaining.next() {
|
||||
if let Some(response) = execute_execution_runtime_stream(
|
||||
state,
|
||||
plan_and_report.plan().clone(),
|
||||
trace_id,
|
||||
decision,
|
||||
plan_kind,
|
||||
plan_and_report.report_kind(),
|
||||
plan_and_report.report_context(),
|
||||
)
|
||||
.await?
|
||||
{
|
||||
mark_unused_local_candidates(state, remaining.collect()).await;
|
||||
return Ok(Some(response));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub(crate) async fn mark_unused_local_candidates<T>(state: &AppState, remaining: Vec<T>)
|
||||
where
|
||||
T: LocalPlanAndReport,
|
||||
{
|
||||
for plan_and_report in remaining {
|
||||
record_local_request_candidate_status(
|
||||
state,
|
||||
plan_and_report.plan(),
|
||||
plan_and_report.report_context().as_ref(),
|
||||
aether_data::repository::candidates::RequestCandidateStatus::Unused,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
use axum::body::{Body, Bytes};
|
||||
use axum::http::Response;
|
||||
|
||||
use crate::gateway::intent;
|
||||
use crate::gateway::{AppState, GatewayControlDecision, GatewayError};
|
||||
|
||||
pub(crate) async fn maybe_execute_sync_local_path(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
body_bytes: &Bytes,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
intent::maybe_execute_via_sync_intent_path(state, parts, body_bytes, trace_id, decision).await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_execute_stream_local_path(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
body_bytes: &Bytes,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
intent::maybe_execute_via_stream_intent_path(state, parts, body_bytes, trace_id, decision).await
|
||||
}
|
||||
@@ -2,10 +2,7 @@ use crate::gateway::{AppState, GatewayControlDecision, GatewayError};
|
||||
|
||||
pub(crate) mod candidate_affinity;
|
||||
pub(crate) mod common;
|
||||
pub(crate) mod contracts;
|
||||
mod decision;
|
||||
pub(crate) mod family_core;
|
||||
pub(crate) mod local_path;
|
||||
pub(crate) mod passthrough;
|
||||
pub(crate) mod plan_builders;
|
||||
pub(crate) mod specialized;
|
||||
@@ -26,7 +23,7 @@ pub(crate) use self::common::{
|
||||
OPENAI_VIDEO_CONTENT_PLAN_KIND, OPENAI_VIDEO_CREATE_SYNC_PLAN_KIND,
|
||||
OPENAI_VIDEO_DELETE_SYNC_PLAN_KIND, OPENAI_VIDEO_REMIX_SYNC_PLAN_KIND,
|
||||
};
|
||||
pub(crate) use self::contracts::{
|
||||
pub(crate) use crate::gateway::ai_pipeline::contracts::{
|
||||
build_gateway_plan_request, generic_decision_missing_exact_provider_request,
|
||||
GatewayControlPlanRequest, GatewayControlPlanResponse, GatewayControlSyncDecisionResponse,
|
||||
};
|
||||
@@ -43,18 +40,12 @@ pub(crate) use crate::gateway::scheduler::{
|
||||
pub(crate) use passthrough::{
|
||||
maybe_build_stream_local_same_format_provider_decision_payload,
|
||||
maybe_build_sync_local_same_format_provider_decision_payload,
|
||||
maybe_execute_stream_via_local_same_format_provider_decision,
|
||||
maybe_execute_sync_via_local_same_format_provider_decision,
|
||||
};
|
||||
pub(crate) use specialized::{
|
||||
maybe_build_stream_local_gemini_files_decision_payload,
|
||||
maybe_build_sync_local_gemini_files_decision_payload,
|
||||
maybe_build_sync_local_video_decision_payload,
|
||||
maybe_execute_stream_via_local_gemini_files_decision,
|
||||
maybe_execute_sync_via_local_gemini_files_decision,
|
||||
maybe_execute_sync_via_local_video_decision,
|
||||
};
|
||||
pub(crate) use local_path::{maybe_execute_stream_local_path, maybe_execute_sync_local_path};
|
||||
pub(crate) use standard::{
|
||||
copy_request_number_field, copy_request_number_field_as,
|
||||
map_openai_reasoning_effort_to_claude_output, map_openai_reasoning_effort_to_gemini_budget,
|
||||
@@ -62,11 +53,7 @@ pub(crate) use standard::{
|
||||
maybe_build_stream_local_openai_cli_decision_payload,
|
||||
maybe_build_stream_local_standard_decision_payload, maybe_build_sync_local_decision_payload,
|
||||
maybe_build_sync_local_openai_cli_decision_payload,
|
||||
maybe_build_sync_local_standard_decision_payload, maybe_execute_stream_via_local_decision,
|
||||
maybe_execute_stream_via_local_openai_cli_decision,
|
||||
maybe_execute_stream_via_local_standard_decision, maybe_execute_sync_via_local_decision,
|
||||
maybe_execute_sync_via_local_openai_cli_decision,
|
||||
maybe_execute_sync_via_local_standard_decision, parse_openai_stop_sequences,
|
||||
maybe_build_sync_local_standard_decision_payload, parse_openai_stop_sequences,
|
||||
resolve_openai_chat_max_tokens, value_as_u64,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
//! Requests that can stay in the same public/provider contract family.
|
||||
|
||||
mod provider;
|
||||
pub(crate) mod provider;
|
||||
|
||||
pub(crate) use self::provider::{
|
||||
maybe_build_stream_local_same_format_provider_decision_payload,
|
||||
maybe_build_sync_local_same_format_provider_decision_payload,
|
||||
maybe_execute_stream_via_local_same_format_provider_decision,
|
||||
maybe_execute_sync_via_local_same_format_provider_decision,
|
||||
};
|
||||
pub(crate) use crate::gateway::provider_transport::provider_type_supports_local_same_format_transport;
|
||||
|
||||
@@ -8,6 +8,13 @@ use serde_json::{json, Value};
|
||||
use tracing::warn;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates;
|
||||
use crate::gateway::ai_pipeline::planner::{
|
||||
EXECUTION_RUNTIME_STREAM_DECISION_ACTION, EXECUTION_RUNTIME_SYNC_DECISION_ACTION,
|
||||
};
|
||||
use crate::gateway::headers::collect_control_headers;
|
||||
use crate::gateway::provider_transport::{
|
||||
apply_local_body_rules, apply_local_header_rules, build_antigravity_safe_v1internal_request,
|
||||
@@ -29,27 +36,17 @@ use crate::gateway::provider_transport::{
|
||||
AntigravityRequestEnvelopeSupport, AntigravityRequestSideSupport, AntigravityRequestUrlAction,
|
||||
LocalResolvedOAuthRequestAuth, KIRO_ENVELOPE_NAME,
|
||||
};
|
||||
use crate::gateway::request_candidates::{
|
||||
current_unix_secs, record_local_request_candidate_status,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates;
|
||||
use crate::gateway::scheduler::{
|
||||
list_selectable_candidates, GatewayMinimalCandidateSelectionCandidate,
|
||||
current_unix_secs, list_selectable_candidates, record_local_request_candidate_status,
|
||||
GatewayMinimalCandidateSelectionCandidate,
|
||||
};
|
||||
use crate::gateway::{
|
||||
append_execution_contract_fields_to_value, execute_execution_runtime_stream,
|
||||
execute_execution_runtime_sync, AppState, ConversionMode, ExecutionStrategy,
|
||||
append_execution_contract_fields_to_value, AppState, ConversionMode, ExecutionStrategy,
|
||||
GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::{
|
||||
EXECUTION_RUNTIME_STREAM_DECISION_ACTION, EXECUTION_RUNTIME_SYNC_DECISION_ACTION,
|
||||
};
|
||||
|
||||
mod family;
|
||||
mod plans;
|
||||
pub(crate) mod family;
|
||||
pub(crate) mod plans;
|
||||
mod request;
|
||||
|
||||
pub(super) use self::family::{
|
||||
@@ -61,12 +58,6 @@ pub(super) use self::family::{
|
||||
pub(crate) use self::family::{
|
||||
maybe_build_stream_local_same_format_provider_decision_payload,
|
||||
maybe_build_sync_local_same_format_provider_decision_payload,
|
||||
maybe_execute_stream_via_local_same_format_provider_decision,
|
||||
maybe_execute_sync_via_local_same_format_provider_decision,
|
||||
};
|
||||
use self::plans::{
|
||||
build_local_stream_plan_and_reports, build_local_sync_plan_and_reports, resolve_stream_spec,
|
||||
resolve_sync_spec,
|
||||
};
|
||||
use self::request::{
|
||||
build_same_format_provider_request_body, build_same_format_upstream_url,
|
||||
|
||||
+4
-59
@@ -1,69 +1,14 @@
|
||||
use axum::body::Body;
|
||||
use axum::http::Response;
|
||||
use crate::gateway::{
|
||||
AppState, GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
};
|
||||
|
||||
use crate::gateway::ai_pipeline::planner::family_core::{
|
||||
execute_stream_plan_and_reports, execute_sync_plan_and_reports,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::{AppState, GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError};
|
||||
|
||||
use super::super::plans::{
|
||||
build_local_stream_plan_and_reports, build_local_sync_plan_and_reports, resolve_stream_spec,
|
||||
resolve_sync_spec,
|
||||
};
|
||||
use super::super::plans::{resolve_stream_spec, resolve_sync_spec};
|
||||
use super::candidates::{
|
||||
materialize_local_same_format_provider_candidate_attempts,
|
||||
resolve_local_same_format_provider_decision_input,
|
||||
};
|
||||
use super::payload::maybe_build_local_same_format_provider_decision_payload_for_candidate;
|
||||
|
||||
pub(crate) async fn maybe_execute_sync_via_local_same_format_provider_decision(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
let Some(spec) = resolve_sync_spec(plan_kind) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let plan_and_reports =
|
||||
build_local_sync_plan_and_reports(state, parts, trace_id, decision, body_json, spec)
|
||||
.await?;
|
||||
if plan_and_reports.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
execute_sync_plan_and_reports(state, parts, trace_id, decision, plan_kind, plan_and_reports)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_execute_stream_via_local_same_format_provider_decision(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
let Some(spec) = resolve_stream_spec(plan_kind) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let plan_and_reports =
|
||||
build_local_stream_plan_and_reports(state, parts, trace_id, decision, body_json, spec)
|
||||
.await?;
|
||||
if plan_and_reports.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
execute_stream_plan_and_reports(state, trace_id, decision, plan_kind, plan_and_reports).await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_build_sync_local_same_format_provider_decision_payload(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
+5
-5
@@ -3,8 +3,7 @@ use serde_json::json;
|
||||
use tracing::warn;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::gateway::request_candidates::current_unix_secs;
|
||||
use crate::gateway::scheduler::list_selectable_candidates;
|
||||
use crate::gateway::scheduler::{current_unix_secs, list_selectable_candidates};
|
||||
use crate::gateway::{
|
||||
append_execution_contract_fields_to_value, AppState, ConversionMode, ExecutionStrategy,
|
||||
GatewayControlDecision, GatewayError,
|
||||
@@ -84,9 +83,10 @@ pub(crate) async fn materialize_local_same_format_provider_candidate_attempts(
|
||||
current_unix_secs(),
|
||||
)
|
||||
.await?;
|
||||
let candidates =
|
||||
crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates(state, candidates)
|
||||
.await;
|
||||
let candidates = crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates(
|
||||
state, candidates,
|
||||
)
|
||||
.await;
|
||||
|
||||
let created_at_unix_secs = current_unix_secs();
|
||||
let mut attempts = Vec::with_capacity(candidates.len());
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
mod build;
|
||||
mod candidates;
|
||||
mod execute;
|
||||
mod payload;
|
||||
mod types;
|
||||
|
||||
pub(crate) use self::build::{
|
||||
maybe_build_stream_local_same_format_provider_decision_payload,
|
||||
maybe_build_sync_local_same_format_provider_decision_payload,
|
||||
};
|
||||
pub(crate) use self::candidates::{
|
||||
materialize_local_same_format_provider_candidate_attempts,
|
||||
resolve_local_same_format_provider_decision_input,
|
||||
};
|
||||
pub(crate) use self::execute::{
|
||||
maybe_build_stream_local_same_format_provider_decision_payload,
|
||||
maybe_build_sync_local_same_format_provider_decision_payload,
|
||||
maybe_execute_stream_via_local_same_format_provider_decision,
|
||||
maybe_execute_sync_via_local_same_format_provider_decision,
|
||||
};
|
||||
pub(crate) use self::payload::maybe_build_local_same_format_provider_decision_payload_for_candidate;
|
||||
pub(crate) use self::types::{LocalSameFormatProviderFamily, LocalSameFormatProviderSpec};
|
||||
|
||||
@@ -21,8 +21,7 @@ use crate::gateway::provider_transport::{
|
||||
AntigravityRequestEnvelopeSupport, AntigravityRequestSideSupport,
|
||||
LocalResolvedOAuthRequestAuth, KIRO_ENVELOPE_NAME,
|
||||
};
|
||||
use crate::gateway::request_candidates::current_unix_secs;
|
||||
use crate::gateway::scheduler::GatewayMinimalCandidateSelectionCandidate;
|
||||
use crate::gateway::scheduler::{current_unix_secs, GatewayMinimalCandidateSelectionCandidate};
|
||||
use crate::gateway::{
|
||||
append_execution_contract_fields_to_value, AppState, ConversionMode, ExecutionStrategy,
|
||||
GatewayControlSyncDecisionResponse, EXECUTION_RUNTIME_STREAM_DECISION_ACTION,
|
||||
|
||||
@@ -17,7 +17,7 @@ use crate::gateway::ai_pipeline::planner::{
|
||||
GEMINI_CLI_STREAM_PLAN_KIND, GEMINI_CLI_SYNC_PLAN_KIND,
|
||||
};
|
||||
|
||||
pub(super) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalSameFormatProviderSpec> {
|
||||
pub(crate) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalSameFormatProviderSpec> {
|
||||
match plan_kind {
|
||||
CLAUDE_CHAT_SYNC_PLAN_KIND => Some(LocalSameFormatProviderSpec {
|
||||
api_format: "claude:chat",
|
||||
@@ -51,7 +51,7 @@ pub(super) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalSameFormatProvid
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn resolve_stream_spec(plan_kind: &str) -> Option<LocalSameFormatProviderSpec> {
|
||||
pub(crate) fn resolve_stream_spec(plan_kind: &str) -> Option<LocalSameFormatProviderSpec> {
|
||||
match plan_kind {
|
||||
CLAUDE_CHAT_STREAM_PLAN_KIND => Some(LocalSameFormatProviderSpec {
|
||||
api_format: "claude:chat",
|
||||
@@ -85,7 +85,7 @@ pub(super) fn resolve_stream_spec(plan_kind: &str) -> Option<LocalSameFormatProv
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn build_local_sync_plan_and_reports(
|
||||
pub(crate) async fn build_local_sync_plan_and_reports(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
@@ -141,7 +141,7 @@ pub(super) async fn build_local_sync_plan_and_reports(
|
||||
Ok(plans)
|
||||
}
|
||||
|
||||
pub(super) async fn build_local_stream_plan_and_reports(
|
||||
pub(crate) async fn build_local_stream_plan_and_reports(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use aether_data::repository::candidates::{RequestCandidateStatus, UpsertRequestCandidateRecord};
|
||||
use axum::body::Body;
|
||||
use axum::http::Response;
|
||||
use serde_json::json;
|
||||
use tracing::warn;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
build_passthrough_stream_plan_from_decision, build_passthrough_sync_plan_from_decision,
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates;
|
||||
use crate::gateway::ai_pipeline::planner::{
|
||||
EXECUTION_RUNTIME_STREAM_DECISION_ACTION, EXECUTION_RUNTIME_SYNC_DECISION_ACTION,
|
||||
GEMINI_FILES_DELETE_PLAN_KIND, GEMINI_FILES_DOWNLOAD_PLAN_KIND, GEMINI_FILES_GET_PLAN_KIND,
|
||||
GEMINI_FILES_LIST_PLAN_KIND, GEMINI_FILES_UPLOAD_PLAN_KIND,
|
||||
};
|
||||
use crate::gateway::headers::collect_control_headers;
|
||||
use crate::gateway::provider_transport::{
|
||||
apply_local_body_rules, apply_local_header_rules, build_gemini_files_passthrough_url,
|
||||
@@ -14,26 +22,12 @@ use crate::gateway::provider_transport::{
|
||||
resolve_transport_execution_timeouts, resolve_transport_proxy_snapshot_with_tunnel_affinity,
|
||||
resolve_transport_tls_profile, supports_local_gemini_transport_with_network,
|
||||
};
|
||||
use crate::gateway::request_candidates::{
|
||||
current_unix_secs, record_local_request_candidate_status,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
build_passthrough_stream_plan_from_decision, build_passthrough_sync_plan_from_decision,
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates;
|
||||
use crate::gateway::scheduler::{
|
||||
list_selectable_candidates_for_required_capability_without_requested_model,
|
||||
GatewayMinimalCandidateSelectionCandidate,
|
||||
current_unix_secs, list_selectable_candidates_for_required_capability_without_requested_model,
|
||||
record_local_request_candidate_status, GatewayMinimalCandidateSelectionCandidate,
|
||||
};
|
||||
use crate::gateway::{
|
||||
execute_execution_runtime_stream, execute_execution_runtime_sync, AppState,
|
||||
GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::{
|
||||
EXECUTION_RUNTIME_STREAM_DECISION_ACTION, EXECUTION_RUNTIME_SYNC_DECISION_ACTION,
|
||||
GEMINI_FILES_DELETE_PLAN_KIND, GEMINI_FILES_DOWNLOAD_PLAN_KIND, GEMINI_FILES_GET_PLAN_KIND,
|
||||
GEMINI_FILES_LIST_PLAN_KIND, GEMINI_FILES_UPLOAD_PLAN_KIND,
|
||||
AppState, GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
};
|
||||
|
||||
const GEMINI_FILES_CANDIDATE_API_FORMAT: &str = "gemini:chat";
|
||||
@@ -60,7 +54,7 @@ struct LocalGeminiFilesCandidateAttempt {
|
||||
candidate_id: String,
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_execute_sync_via_local_gemini_files_decision(
|
||||
pub(crate) async fn build_local_gemini_files_sync_plan_and_reports_for_kind(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
body_json: &serde_json::Value,
|
||||
@@ -69,12 +63,12 @@ pub(crate) async fn maybe_execute_sync_via_local_gemini_files_decision(
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
) -> Result<Vec<LocalSyncPlanAndReport>, GatewayError> {
|
||||
let Some(spec) = resolve_sync_spec(plan_kind) else {
|
||||
return Ok(None);
|
||||
return Ok(Vec::new());
|
||||
};
|
||||
|
||||
let plan_and_reports = build_local_sync_plan_and_reports(
|
||||
build_local_sync_plan_and_reports(
|
||||
state,
|
||||
parts,
|
||||
body_json,
|
||||
@@ -84,69 +78,21 @@ pub(crate) async fn maybe_execute_sync_via_local_gemini_files_decision(
|
||||
decision,
|
||||
spec,
|
||||
)
|
||||
.await?;
|
||||
if plan_and_reports.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut remaining = plan_and_reports.into_iter();
|
||||
while let Some(plan_and_report) = remaining.next() {
|
||||
if let Some(response) = execute_execution_runtime_sync(
|
||||
state,
|
||||
parts.uri.path(),
|
||||
plan_and_report.plan,
|
||||
trace_id,
|
||||
decision,
|
||||
plan_kind,
|
||||
plan_and_report.report_kind,
|
||||
plan_and_report.report_context,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
mark_unused_local_files_candidates(state, remaining.collect()).await;
|
||||
return Ok(Some(response));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_execute_stream_via_local_gemini_files_decision(
|
||||
pub(crate) async fn build_local_gemini_files_stream_plan_and_reports_for_kind(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
) -> Result<Vec<LocalStreamPlanAndReport>, GatewayError> {
|
||||
let Some(spec) = resolve_stream_spec(plan_kind) else {
|
||||
return Ok(None);
|
||||
return Ok(Vec::new());
|
||||
};
|
||||
|
||||
let plan_and_reports =
|
||||
build_local_stream_plan_and_reports(state, parts, trace_id, decision, spec).await?;
|
||||
if plan_and_reports.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut remaining = plan_and_reports.into_iter();
|
||||
while let Some(plan_and_report) = remaining.next() {
|
||||
if let Some(response) = execute_execution_runtime_stream(
|
||||
state,
|
||||
plan_and_report.plan,
|
||||
trace_id,
|
||||
decision,
|
||||
plan_kind,
|
||||
plan_and_report.report_kind,
|
||||
plan_and_report.report_context,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
mark_unused_local_files_candidates(state, remaining.collect()).await;
|
||||
return Ok(Some(response));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
build_local_stream_plan_and_reports(state, parts, trace_id, decision, spec).await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_build_sync_local_gemini_files_decision_payload(
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
//! Non-matrix AI surfaces such as files and video.
|
||||
|
||||
mod files;
|
||||
mod video;
|
||||
pub(crate) mod files;
|
||||
pub(crate) mod video;
|
||||
|
||||
pub(crate) use self::files::{
|
||||
maybe_build_stream_local_gemini_files_decision_payload,
|
||||
maybe_build_sync_local_gemini_files_decision_payload,
|
||||
maybe_execute_stream_via_local_gemini_files_decision,
|
||||
maybe_execute_sync_via_local_gemini_files_decision,
|
||||
};
|
||||
pub(crate) use self::video::{
|
||||
maybe_build_sync_local_video_decision_payload, maybe_execute_sync_via_local_video_decision,
|
||||
};
|
||||
pub(crate) use self::video::maybe_build_sync_local_video_decision_payload;
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use aether_data::repository::candidates::{RequestCandidateStatus, UpsertRequestCandidateRecord};
|
||||
use axum::body::Body;
|
||||
use axum::http::Response;
|
||||
use serde_json::{json, Value};
|
||||
use tracing::warn;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
build_passthrough_sync_plan_from_decision, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates;
|
||||
use crate::gateway::ai_pipeline::planner::{
|
||||
EXECUTION_RUNTIME_SYNC_DECISION_ACTION, GEMINI_VIDEO_CREATE_SYNC_PLAN_KIND,
|
||||
OPENAI_VIDEO_CREATE_SYNC_PLAN_KIND,
|
||||
};
|
||||
use crate::gateway::headers::collect_control_headers;
|
||||
use crate::gateway::provider_transport::{
|
||||
apply_local_body_rules, apply_local_header_rules, build_gemini_video_predict_long_running_url,
|
||||
@@ -15,23 +21,12 @@ use crate::gateway::provider_transport::{
|
||||
resolve_transport_proxy_snapshot_with_tunnel_affinity, resolve_transport_tls_profile,
|
||||
supports_local_gemini_transport_with_network, supports_local_standard_transport_with_network,
|
||||
};
|
||||
use crate::gateway::request_candidates::{
|
||||
current_unix_secs, record_local_request_candidate_status,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
build_passthrough_sync_plan_from_decision, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates;
|
||||
use crate::gateway::scheduler::{
|
||||
list_selectable_candidates, GatewayMinimalCandidateSelectionCandidate,
|
||||
current_unix_secs, list_selectable_candidates, record_local_request_candidate_status,
|
||||
GatewayMinimalCandidateSelectionCandidate,
|
||||
};
|
||||
use crate::gateway::{
|
||||
execute_execution_runtime_sync, AppState, GatewayControlDecision,
|
||||
GatewayControlSyncDecisionResponse, GatewayError,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::{
|
||||
EXECUTION_RUNTIME_SYNC_DECISION_ACTION, GEMINI_VIDEO_CREATE_SYNC_PLAN_KIND,
|
||||
OPENAI_VIDEO_CREATE_SYNC_PLAN_KIND,
|
||||
AppState, GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -62,45 +57,19 @@ struct LocalVideoCreateCandidateAttempt {
|
||||
candidate_id: String,
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_execute_sync_via_local_video_decision(
|
||||
pub(crate) async fn build_local_video_sync_plan_and_reports_for_kind(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
body_json: &serde_json::Value,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
) -> Result<Vec<LocalSyncPlanAndReport>, GatewayError> {
|
||||
let Some(spec) = resolve_sync_spec(plan_kind) else {
|
||||
return Ok(None);
|
||||
return Ok(Vec::new());
|
||||
};
|
||||
|
||||
let plan_and_reports =
|
||||
build_local_sync_plan_and_reports(state, parts, body_json, trace_id, decision, spec)
|
||||
.await?;
|
||||
if plan_and_reports.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut remaining = plan_and_reports.into_iter();
|
||||
while let Some(plan_and_report) = remaining.next() {
|
||||
if let Some(response) = execute_execution_runtime_sync(
|
||||
state,
|
||||
parts.uri.path(),
|
||||
plan_and_report.plan,
|
||||
trace_id,
|
||||
decision,
|
||||
plan_kind,
|
||||
plan_and_report.report_kind,
|
||||
plan_and_report.report_context,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
mark_unused_local_video_candidates(state, remaining.collect()).await;
|
||||
return Ok(Some(response));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
build_local_sync_plan_and_reports(state, parts, body_json, trace_id, decision, spec).await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_build_sync_local_video_decision_payload(
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::gateway::ai_pipeline::planner::{
|
||||
|
||||
use super::super::family::{LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec};
|
||||
|
||||
pub(super) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
pub(crate) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
match plan_kind {
|
||||
CLAUDE_CHAT_SYNC_PLAN_KIND => Some(LocalStandardSpec {
|
||||
api_format: "claude:chat",
|
||||
@@ -18,7 +18,7 @@ pub(super) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn resolve_stream_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
pub(crate) fn resolve_stream_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
match plan_kind {
|
||||
CLAUDE_CHAT_STREAM_PLAN_KIND => Some(LocalStandardSpec {
|
||||
api_format: "claude:chat",
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::gateway::ai_pipeline::planner::{
|
||||
|
||||
use super::super::family::{LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec};
|
||||
|
||||
pub(super) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
pub(crate) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
match plan_kind {
|
||||
CLAUDE_CLI_SYNC_PLAN_KIND => Some(LocalStandardSpec {
|
||||
api_format: "claude:cli",
|
||||
@@ -18,7 +18,7 @@ pub(super) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn resolve_stream_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
pub(crate) fn resolve_stream_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
match plan_kind {
|
||||
CLAUDE_CLI_STREAM_PLAN_KIND => Some(LocalStandardSpec {
|
||||
api_format: "claude:cli",
|
||||
|
||||
@@ -1,63 +1,14 @@
|
||||
use axum::body::Body;
|
||||
use axum::http::Response;
|
||||
|
||||
use crate::gateway::{
|
||||
AppState, GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
};
|
||||
|
||||
use super::family::{
|
||||
maybe_build_stream_via_standard_family_payload, maybe_build_sync_via_standard_family_payload,
|
||||
maybe_execute_stream_via_standard_family_decision,
|
||||
maybe_execute_sync_via_standard_family_decision,
|
||||
};
|
||||
pub(crate) use crate::gateway::ai_pipeline::conversion::request::normalize_claude_request_to_openai_chat_request;
|
||||
|
||||
mod chat;
|
||||
mod cli;
|
||||
|
||||
pub(crate) async fn maybe_execute_sync_via_local_claude_decision(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
maybe_execute_sync_via_standard_family_decision(
|
||||
state,
|
||||
parts,
|
||||
trace_id,
|
||||
decision,
|
||||
body_json,
|
||||
plan_kind,
|
||||
|plan_kind| {
|
||||
chat::resolve_sync_spec(plan_kind).or_else(|| cli::resolve_sync_spec(plan_kind))
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_execute_stream_via_local_claude_decision(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
maybe_execute_stream_via_standard_family_decision(
|
||||
state,
|
||||
parts,
|
||||
trace_id,
|
||||
decision,
|
||||
body_json,
|
||||
plan_kind,
|
||||
|plan_kind| {
|
||||
chat::resolve_stream_spec(plan_kind).or_else(|| cli::resolve_stream_spec(plan_kind))
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
pub(crate) mod chat;
|
||||
pub(crate) mod cli;
|
||||
|
||||
pub(crate) async fn maybe_build_sync_local_claude_decision_payload(
|
||||
state: &AppState,
|
||||
|
||||
+5
-55
@@ -1,16 +1,13 @@
|
||||
use axum::body::Body;
|
||||
use axum::http::Response;
|
||||
use tracing::warn;
|
||||
|
||||
use crate::gateway::ai_pipeline::planner::family_core::{
|
||||
execute_stream_plan_and_reports, execute_sync_plan_and_reports,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
build_gemini_stream_plan_from_decision, build_gemini_sync_plan_from_decision,
|
||||
build_standard_stream_plan_from_decision, build_standard_sync_plan_from_decision,
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::{AppState, GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError};
|
||||
use crate::gateway::{
|
||||
AppState, GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
};
|
||||
|
||||
use super::candidates::{
|
||||
materialize_local_standard_candidate_attempts, resolve_local_standard_decision_input,
|
||||
@@ -18,53 +15,6 @@ use super::candidates::{
|
||||
use super::payload::maybe_build_local_standard_decision_payload_for_candidate;
|
||||
use super::types::{LocalStandardSourceFamily, LocalStandardSpec};
|
||||
|
||||
pub(crate) async fn maybe_execute_sync_via_standard_family_decision(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
resolve_sync_spec: fn(&str) -> Option<LocalStandardSpec>,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
let Some(spec) = resolve_sync_spec(plan_kind) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let plan_and_reports =
|
||||
build_local_sync_plan_and_reports(state, parts, trace_id, decision, body_json, spec)
|
||||
.await?;
|
||||
if plan_and_reports.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
execute_sync_plan_and_reports(state, parts, trace_id, decision, plan_kind, plan_and_reports)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_execute_stream_via_standard_family_decision(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
resolve_stream_spec: fn(&str) -> Option<LocalStandardSpec>,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
let Some(spec) = resolve_stream_spec(plan_kind) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let plan_and_reports =
|
||||
build_local_stream_plan_and_reports(state, parts, trace_id, decision, body_json, spec)
|
||||
.await?;
|
||||
if plan_and_reports.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
execute_stream_plan_and_reports(state, trace_id, decision, plan_kind, plan_and_reports).await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_build_sync_via_standard_family_payload(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
@@ -137,7 +87,7 @@ pub(crate) async fn maybe_build_stream_via_standard_family_payload(
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
async fn build_local_sync_plan_and_reports(
|
||||
pub(crate) async fn build_local_sync_plan_and_reports(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
@@ -186,7 +136,7 @@ async fn build_local_sync_plan_and_reports(
|
||||
Ok(plans)
|
||||
}
|
||||
|
||||
async fn build_local_stream_plan_and_reports(
|
||||
pub(crate) async fn build_local_stream_plan_and_reports(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
@@ -5,9 +5,8 @@ use serde_json::json;
|
||||
use tracing::warn;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::gateway::request_candidates::current_unix_secs;
|
||||
use crate::gateway::scheduler::{
|
||||
list_selectable_candidates, GatewayMinimalCandidateSelectionCandidate,
|
||||
current_unix_secs, list_selectable_candidates, GatewayMinimalCandidateSelectionCandidate,
|
||||
};
|
||||
use crate::gateway::{
|
||||
append_execution_contract_fields_to_value, AppState, ConversionMode, ExecutionStrategy,
|
||||
@@ -118,9 +117,10 @@ pub(super) async fn materialize_local_standard_candidate_attempts(
|
||||
}
|
||||
}
|
||||
}
|
||||
let candidates =
|
||||
crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates(state, candidates)
|
||||
.await;
|
||||
let candidates = crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates(
|
||||
state, candidates,
|
||||
)
|
||||
.await;
|
||||
|
||||
let created_at_unix_secs = current_unix_secs();
|
||||
let mut attempts = Vec::with_capacity(candidates.len());
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
mod build;
|
||||
mod candidates;
|
||||
mod execute;
|
||||
mod payload;
|
||||
mod types;
|
||||
|
||||
pub(crate) use self::execute::{
|
||||
pub(crate) use self::build::{
|
||||
build_local_stream_plan_and_reports, build_local_sync_plan_and_reports,
|
||||
maybe_build_stream_via_standard_family_payload, maybe_build_sync_via_standard_family_payload,
|
||||
maybe_execute_stream_via_standard_family_decision,
|
||||
maybe_execute_sync_via_standard_family_decision,
|
||||
};
|
||||
pub(crate) use self::types::{
|
||||
LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec,
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::gateway::provider_transport::{
|
||||
resolve_transport_execution_timeouts, resolve_transport_proxy_snapshot_with_tunnel_affinity,
|
||||
resolve_transport_tls_profile, LocalResolvedOAuthRequestAuth,
|
||||
};
|
||||
use crate::gateway::request_candidates::current_unix_secs;
|
||||
use crate::gateway::scheduler::current_unix_secs;
|
||||
use crate::gateway::{
|
||||
append_execution_contract_fields_to_value, AppState, ConversionMode, ExecutionStrategy,
|
||||
GatewayControlSyncDecisionResponse, EXECUTION_RUNTIME_STREAM_DECISION_ACTION,
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::gateway::ai_pipeline::planner::{
|
||||
|
||||
use super::super::family::{LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec};
|
||||
|
||||
pub(super) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
pub(crate) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
match plan_kind {
|
||||
GEMINI_CHAT_SYNC_PLAN_KIND => Some(LocalStandardSpec {
|
||||
api_format: "gemini:chat",
|
||||
@@ -18,7 +18,7 @@ pub(super) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn resolve_stream_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
pub(crate) fn resolve_stream_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
match plan_kind {
|
||||
GEMINI_CHAT_STREAM_PLAN_KIND => Some(LocalStandardSpec {
|
||||
api_format: "gemini:chat",
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::gateway::ai_pipeline::planner::{
|
||||
|
||||
use super::super::family::{LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec};
|
||||
|
||||
pub(super) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
pub(crate) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
match plan_kind {
|
||||
GEMINI_CLI_SYNC_PLAN_KIND => Some(LocalStandardSpec {
|
||||
api_format: "gemini:cli",
|
||||
@@ -18,7 +18,7 @@ pub(super) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn resolve_stream_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
pub(crate) fn resolve_stream_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||
match plan_kind {
|
||||
GEMINI_CLI_STREAM_PLAN_KIND => Some(LocalStandardSpec {
|
||||
api_format: "gemini:cli",
|
||||
|
||||
@@ -1,63 +1,14 @@
|
||||
use axum::body::Body;
|
||||
use axum::http::Response;
|
||||
|
||||
use crate::gateway::{
|
||||
AppState, GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
};
|
||||
|
||||
use super::family::{
|
||||
maybe_build_stream_via_standard_family_payload, maybe_build_sync_via_standard_family_payload,
|
||||
maybe_execute_stream_via_standard_family_decision,
|
||||
maybe_execute_sync_via_standard_family_decision,
|
||||
};
|
||||
pub(crate) use crate::gateway::ai_pipeline::conversion::request::normalize_gemini_request_to_openai_chat_request;
|
||||
|
||||
mod chat;
|
||||
mod cli;
|
||||
|
||||
pub(crate) async fn maybe_execute_sync_via_local_gemini_decision(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
maybe_execute_sync_via_standard_family_decision(
|
||||
state,
|
||||
parts,
|
||||
trace_id,
|
||||
decision,
|
||||
body_json,
|
||||
plan_kind,
|
||||
|plan_kind| {
|
||||
chat::resolve_sync_spec(plan_kind).or_else(|| cli::resolve_sync_spec(plan_kind))
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_execute_stream_via_local_gemini_decision(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
maybe_execute_stream_via_standard_family_decision(
|
||||
state,
|
||||
parts,
|
||||
trace_id,
|
||||
decision,
|
||||
body_json,
|
||||
plan_kind,
|
||||
|plan_kind| {
|
||||
chat::resolve_stream_spec(plan_kind).or_else(|| cli::resolve_stream_spec(plan_kind))
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
pub(crate) mod chat;
|
||||
pub(crate) mod cli;
|
||||
|
||||
pub(crate) async fn maybe_build_sync_local_gemini_decision_payload(
|
||||
state: &AppState,
|
||||
|
||||
@@ -1,88 +1,51 @@
|
||||
//! Standard contract planning surface.
|
||||
//!
|
||||
//! This groups the public standard matrix in one place:
|
||||
//! request-side conversion, matrix registry, and local standard execution entrypoints.
|
||||
|
||||
use axum::body::Body;
|
||||
use axum::http::Response;
|
||||
//! This groups the standard planning surface in one place:
|
||||
//! request-side conversion, matrix registry, and decision payload builders.
|
||||
|
||||
use crate::gateway::{
|
||||
AppState, GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
};
|
||||
|
||||
pub(crate) mod claude;
|
||||
mod family;
|
||||
pub(crate) mod family;
|
||||
pub(crate) mod gemini;
|
||||
mod matrix;
|
||||
pub(crate) mod openai;
|
||||
mod normalize;
|
||||
pub(crate) mod openai_chat;
|
||||
pub(crate) mod openai_cli;
|
||||
|
||||
pub(crate) use self::matrix::{
|
||||
build_standard_request_body, build_standard_upstream_url,
|
||||
normalize_standard_request_to_openai_chat_request,
|
||||
};
|
||||
pub(crate) use self::normalize::{
|
||||
build_cross_format_openai_chat_request_body, build_cross_format_openai_chat_upstream_url,
|
||||
build_cross_format_openai_cli_request_body, build_cross_format_openai_cli_upstream_url,
|
||||
build_local_openai_chat_request_body, build_local_openai_chat_upstream_url,
|
||||
build_local_openai_cli_request_body, build_local_openai_cli_upstream_url,
|
||||
};
|
||||
pub(crate) use self::openai_chat::{
|
||||
copy_request_number_field, copy_request_number_field_as,
|
||||
map_openai_reasoning_effort_to_claude_output, map_openai_reasoning_effort_to_gemini_budget,
|
||||
maybe_build_stream_local_decision_payload, maybe_build_sync_local_decision_payload,
|
||||
parse_openai_stop_sequences, resolve_openai_chat_max_tokens, value_as_u64,
|
||||
};
|
||||
pub(crate) use self::openai_cli::{
|
||||
maybe_build_stream_local_openai_cli_decision_payload,
|
||||
maybe_build_sync_local_openai_cli_decision_payload,
|
||||
};
|
||||
pub(crate) use crate::gateway::ai_pipeline::conversion::request::{
|
||||
convert_openai_chat_request_to_claude_request, convert_openai_chat_request_to_gemini_request,
|
||||
convert_openai_chat_request_to_openai_cli_request, extract_openai_text_content,
|
||||
normalize_openai_cli_request_to_openai_chat_request, parse_openai_tool_result_content,
|
||||
};
|
||||
pub(crate) use crate::gateway::ai_pipeline::conversion::{
|
||||
build_core_error_body_for_client_format, request_conversion_kind,
|
||||
request_conversion_transport_supported, sync_chat_response_conversion_kind,
|
||||
sync_cli_response_conversion_kind, RequestConversionKind, SyncChatResponseConversionKind,
|
||||
SyncCliResponseConversionKind,
|
||||
};
|
||||
pub(crate) use self::matrix::{
|
||||
build_standard_request_body, build_standard_upstream_url,
|
||||
normalize_standard_request_to_openai_chat_request,
|
||||
};
|
||||
pub(crate) use self::openai::{
|
||||
copy_request_number_field, copy_request_number_field_as,
|
||||
map_openai_reasoning_effort_to_claude_output, map_openai_reasoning_effort_to_gemini_budget,
|
||||
maybe_build_stream_local_decision_payload, maybe_build_sync_local_decision_payload,
|
||||
maybe_execute_stream_via_local_decision, maybe_execute_sync_via_local_decision,
|
||||
parse_openai_stop_sequences, resolve_openai_chat_max_tokens, value_as_u64,
|
||||
};
|
||||
pub(crate) use self::openai::{
|
||||
maybe_build_stream_local_openai_cli_decision_payload,
|
||||
maybe_build_sync_local_openai_cli_decision_payload,
|
||||
maybe_execute_stream_via_local_openai_cli_decision,
|
||||
maybe_execute_sync_via_local_openai_cli_decision,
|
||||
};
|
||||
|
||||
pub(crate) async fn maybe_execute_sync_via_local_standard_decision(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
if let Some(response) = self::claude::maybe_execute_sync_via_local_claude_decision(
|
||||
state, parts, trace_id, decision, body_json, plan_kind,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(Some(response));
|
||||
}
|
||||
|
||||
self::gemini::maybe_execute_sync_via_local_gemini_decision(
|
||||
state, parts, trace_id, decision, body_json, plan_kind,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_execute_stream_via_local_standard_decision(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
if let Some(response) = self::claude::maybe_execute_stream_via_local_claude_decision(
|
||||
state, parts, trace_id, decision, body_json, plan_kind,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(Some(response));
|
||||
}
|
||||
|
||||
self::gemini::maybe_execute_stream_via_local_gemini_decision(
|
||||
state, parts, trace_id, decision, body_json, plan_kind,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_build_sync_local_standard_decision_payload(
|
||||
state: &AppState,
|
||||
|
||||
+131
-2
@@ -11,10 +11,139 @@ use crate::gateway::ai_pipeline::conversion::request::{
|
||||
use crate::gateway::ai_pipeline::conversion::{request_conversion_kind, RequestConversionKind};
|
||||
use crate::gateway::provider_transport::{
|
||||
apply_local_body_rules, build_antigravity_v1internal_url, build_claude_messages_url,
|
||||
build_gemini_content_url, build_openai_cli_url, build_passthrough_path_url,
|
||||
AntigravityRequestUrlAction,
|
||||
build_gemini_content_url, build_openai_chat_url, build_openai_cli_url,
|
||||
build_passthrough_path_url, AntigravityRequestUrlAction,
|
||||
};
|
||||
|
||||
pub(crate) fn build_local_openai_chat_request_body(
|
||||
body_json: &Value,
|
||||
mapped_model: &str,
|
||||
upstream_is_stream: bool,
|
||||
body_rules: Option<&Value>,
|
||||
) -> Option<Value> {
|
||||
let request_body_object = body_json.as_object()?;
|
||||
let mut provider_request_body = serde_json::Map::from_iter(
|
||||
request_body_object
|
||||
.iter()
|
||||
.map(|(key, value)| (key.clone(), value.clone())),
|
||||
);
|
||||
provider_request_body.insert("model".to_string(), Value::String(mapped_model.to_string()));
|
||||
if upstream_is_stream {
|
||||
provider_request_body.insert("stream".to_string(), Value::Bool(true));
|
||||
}
|
||||
let mut provider_request_body = Value::Object(provider_request_body);
|
||||
if !apply_local_body_rules(&mut provider_request_body, body_rules, Some(body_json)) {
|
||||
return None;
|
||||
}
|
||||
Some(provider_request_body)
|
||||
}
|
||||
|
||||
pub(crate) fn build_local_openai_chat_upstream_url(
|
||||
parts: &http::request::Parts,
|
||||
transport: &crate::gateway::provider_transport::GatewayProviderTransportSnapshot,
|
||||
) -> Option<String> {
|
||||
let custom_path = transport
|
||||
.endpoint
|
||||
.custom_path
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty());
|
||||
|
||||
match custom_path {
|
||||
Some(path) => {
|
||||
build_passthrough_path_url(&transport.endpoint.base_url, path, parts.uri.query(), &[])
|
||||
}
|
||||
None => Some(build_openai_chat_url(
|
||||
&transport.endpoint.base_url,
|
||||
parts.uri.query(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build_cross_format_openai_chat_request_body(
|
||||
body_json: &Value,
|
||||
mapped_model: &str,
|
||||
provider_api_format: &str,
|
||||
upstream_is_stream: bool,
|
||||
body_rules: Option<&Value>,
|
||||
) -> Option<Value> {
|
||||
let conversion_kind = request_conversion_kind("openai:chat", provider_api_format)?;
|
||||
let mut provider_request_body = match conversion_kind {
|
||||
RequestConversionKind::ToClaudeStandard => convert_openai_chat_request_to_claude_request(
|
||||
body_json,
|
||||
mapped_model,
|
||||
upstream_is_stream,
|
||||
)?,
|
||||
RequestConversionKind::ToGeminiStandard => convert_openai_chat_request_to_gemini_request(
|
||||
body_json,
|
||||
mapped_model,
|
||||
upstream_is_stream,
|
||||
)?,
|
||||
RequestConversionKind::ToOpenAIFamilyCli => {
|
||||
convert_openai_chat_request_to_openai_cli_request(
|
||||
body_json,
|
||||
mapped_model,
|
||||
upstream_is_stream,
|
||||
false,
|
||||
)?
|
||||
}
|
||||
RequestConversionKind::ToOpenAICompact => {
|
||||
convert_openai_chat_request_to_openai_cli_request(body_json, mapped_model, false, true)?
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
if !apply_local_body_rules(&mut provider_request_body, body_rules, Some(body_json)) {
|
||||
return None;
|
||||
}
|
||||
Some(provider_request_body)
|
||||
}
|
||||
|
||||
pub(crate) fn build_cross_format_openai_chat_upstream_url(
|
||||
parts: &http::request::Parts,
|
||||
transport: &crate::gateway::provider_transport::GatewayProviderTransportSnapshot,
|
||||
mapped_model: &str,
|
||||
provider_api_format: &str,
|
||||
upstream_is_stream: bool,
|
||||
) -> Option<String> {
|
||||
let conversion_kind = request_conversion_kind("openai:chat", provider_api_format)?;
|
||||
let custom_path = transport
|
||||
.endpoint
|
||||
.custom_path
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty());
|
||||
|
||||
match custom_path {
|
||||
Some(path) => {
|
||||
build_passthrough_path_url(&transport.endpoint.base_url, path, parts.uri.query(), &[])
|
||||
}
|
||||
None => match conversion_kind {
|
||||
RequestConversionKind::ToClaudeStandard => Some(build_claude_messages_url(
|
||||
&transport.endpoint.base_url,
|
||||
parts.uri.query(),
|
||||
)),
|
||||
RequestConversionKind::ToGeminiStandard => build_gemini_content_url(
|
||||
&transport.endpoint.base_url,
|
||||
mapped_model,
|
||||
upstream_is_stream,
|
||||
parts.uri.query(),
|
||||
),
|
||||
RequestConversionKind::ToOpenAIFamilyCli => Some(build_openai_cli_url(
|
||||
&transport.endpoint.base_url,
|
||||
parts.uri.query(),
|
||||
false,
|
||||
)),
|
||||
RequestConversionKind::ToOpenAICompact => Some(build_openai_cli_url(
|
||||
&transport.endpoint.base_url,
|
||||
parts.uri.query(),
|
||||
true,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build_local_openai_cli_request_body(
|
||||
body_json: &Value,
|
||||
mapped_model: &str,
|
||||
@@ -8,6 +8,14 @@ use uuid::Uuid;
|
||||
use crate::gateway::ai_pipeline::conversion::{
|
||||
request_conversion_direct_auth, request_conversion_kind, request_conversion_transport_supported,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates;
|
||||
use crate::gateway::ai_pipeline::planner::{
|
||||
EXECUTION_RUNTIME_STREAM_DECISION_ACTION, EXECUTION_RUNTIME_SYNC_DECISION_ACTION,
|
||||
OPENAI_CHAT_STREAM_PLAN_KIND,
|
||||
};
|
||||
use crate::gateway::headers::collect_control_headers;
|
||||
use crate::gateway::provider_transport::{
|
||||
apply_local_header_rules, build_openai_passthrough_headers, ensure_upstream_auth_header,
|
||||
@@ -15,23 +23,16 @@ use crate::gateway::provider_transport::{
|
||||
resolve_transport_proxy_snapshot_with_tunnel_affinity, resolve_transport_tls_profile,
|
||||
supports_local_openai_chat_transport, LocalResolvedOAuthRequestAuth,
|
||||
};
|
||||
use crate::gateway::request_candidates::record_local_request_candidate_status;
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
use crate::gateway::scheduler::{
|
||||
record_local_request_candidate_status, GatewayMinimalCandidateSelectionCandidate,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates;
|
||||
use crate::gateway::scheduler::GatewayMinimalCandidateSelectionCandidate;
|
||||
use crate::gateway::{
|
||||
append_execution_contract_fields_to_value, AppState, ConversionMode, ExecutionStrategy,
|
||||
GatewayControlSyncDecisionResponse,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::{
|
||||
EXECUTION_RUNTIME_STREAM_DECISION_ACTION, EXECUTION_RUNTIME_SYNC_DECISION_ACTION,
|
||||
OPENAI_CHAT_STREAM_PLAN_KIND,
|
||||
};
|
||||
|
||||
use super::plans::current_unix_secs;
|
||||
use crate::gateway::ai_pipeline::planner::standard::openai::{
|
||||
use crate::gateway::ai_pipeline::planner::standard::{
|
||||
build_cross_format_openai_chat_request_body, build_cross_format_openai_chat_upstream_url,
|
||||
build_local_openai_chat_request_body, build_local_openai_chat_upstream_url,
|
||||
};
|
||||
|
||||
@@ -13,12 +13,12 @@ use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates;
|
||||
use crate::gateway::scheduler::{
|
||||
list_selectable_candidates, GatewayMinimalCandidateSelectionCandidate,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::{
|
||||
OPENAI_CHAT_STREAM_PLAN_KIND, OPENAI_CHAT_SYNC_PLAN_KIND,
|
||||
};
|
||||
use crate::gateway::scheduler::{
|
||||
list_selectable_candidates, GatewayMinimalCandidateSelectionCandidate,
|
||||
};
|
||||
|
||||
pub(super) fn build_local_openai_chat_miss_diagnostic(
|
||||
decision: &GatewayControlDecision,
|
||||
|
||||
@@ -5,12 +5,19 @@ use serde_json::{json, Value};
|
||||
use tracing::warn;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::gateway::ai_pipeline::planner::standard::openai::{
|
||||
use crate::gateway::ai_pipeline::conversion::{
|
||||
request_conversion_direct_auth, request_conversion_kind, request_conversion_transport_supported,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates;
|
||||
use crate::gateway::ai_pipeline::planner::standard::{
|
||||
build_cross_format_openai_cli_request_body, build_cross_format_openai_cli_upstream_url,
|
||||
build_local_openai_cli_request_body, build_local_openai_cli_upstream_url,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::conversion::{
|
||||
request_conversion_direct_auth, request_conversion_kind, request_conversion_transport_supported,
|
||||
use crate::gateway::ai_pipeline::planner::{
|
||||
EXECUTION_RUNTIME_STREAM_DECISION_ACTION, EXECUTION_RUNTIME_SYNC_DECISION_ACTION,
|
||||
};
|
||||
use crate::gateway::headers::collect_control_headers;
|
||||
use crate::gateway::provider_transport::{
|
||||
@@ -23,23 +30,14 @@ use crate::gateway::provider_transport::{
|
||||
AntigravityRequestEnvelopeSupport, AntigravityRequestSideSupport,
|
||||
LocalResolvedOAuthRequestAuth,
|
||||
};
|
||||
use crate::gateway::request_candidates::{
|
||||
current_unix_secs, record_local_request_candidate_status,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::prefer_local_tunnel_owner_candidates;
|
||||
use crate::gateway::scheduler::{
|
||||
list_selectable_candidates, GatewayMinimalCandidateSelectionCandidate,
|
||||
current_unix_secs, list_selectable_candidates, record_local_request_candidate_status,
|
||||
GatewayMinimalCandidateSelectionCandidate,
|
||||
};
|
||||
use crate::gateway::{
|
||||
append_execution_contract_fields_to_value, AppState, ConversionMode, ExecutionStrategy,
|
||||
GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::{
|
||||
EXECUTION_RUNTIME_STREAM_DECISION_ACTION, EXECUTION_RUNTIME_SYNC_DECISION_ACTION,
|
||||
};
|
||||
|
||||
const ANTIGRAVITY_ENVELOPE_NAME: &str = "antigravity:v1internal";
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@ use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
build_openai_cli_stream_plan_from_decision, build_openai_cli_sync_plan_from_decision,
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::{AppState, GatewayControlDecision, GatewayError};
|
||||
use crate::gateway::ai_pipeline::planner::{
|
||||
OPENAI_CLI_STREAM_PLAN_KIND, OPENAI_CLI_SYNC_PLAN_KIND, OPENAI_COMPACT_STREAM_PLAN_KIND,
|
||||
OPENAI_COMPACT_SYNC_PLAN_KIND,
|
||||
};
|
||||
use crate::gateway::{AppState, GatewayControlDecision, GatewayError};
|
||||
|
||||
pub(super) fn resolve_sync_spec(plan_kind: &str) -> Option<LocalOpenAiCliSpec> {
|
||||
match plan_kind {
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
mod chat;
|
||||
mod cli;
|
||||
mod normalize_chat;
|
||||
mod normalize_cli;
|
||||
|
||||
pub(crate) use crate::gateway::ai_pipeline::conversion::request::{
|
||||
convert_openai_chat_request_to_claude_request, convert_openai_chat_request_to_gemini_request,
|
||||
convert_openai_chat_request_to_openai_cli_request, extract_openai_text_content,
|
||||
normalize_openai_cli_request_to_openai_chat_request, parse_openai_tool_result_content,
|
||||
};
|
||||
pub(crate) use self::chat::{
|
||||
copy_request_number_field, copy_request_number_field_as,
|
||||
map_openai_reasoning_effort_to_claude_output, map_openai_reasoning_effort_to_gemini_budget,
|
||||
maybe_build_stream_local_decision_payload, maybe_build_sync_local_decision_payload,
|
||||
maybe_execute_stream_via_local_decision, maybe_execute_sync_via_local_decision,
|
||||
parse_openai_stop_sequences, resolve_openai_chat_max_tokens, value_as_u64,
|
||||
};
|
||||
pub(crate) use self::cli::{
|
||||
maybe_build_stream_local_openai_cli_decision_payload,
|
||||
maybe_build_sync_local_openai_cli_decision_payload,
|
||||
maybe_execute_stream_via_local_openai_cli_decision,
|
||||
maybe_execute_sync_via_local_openai_cli_decision,
|
||||
};
|
||||
pub(crate) use self::normalize_chat::{
|
||||
build_cross_format_openai_chat_request_body, build_cross_format_openai_chat_upstream_url,
|
||||
build_local_openai_chat_request_body, build_local_openai_chat_upstream_url,
|
||||
};
|
||||
pub(crate) use self::normalize_cli::{
|
||||
build_cross_format_openai_cli_request_body, build_cross_format_openai_cli_upstream_url,
|
||||
build_local_openai_cli_request_body, build_local_openai_cli_upstream_url,
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
mod request;
|
||||
pub(crate) use self::request::{
|
||||
build_cross_format_openai_chat_request_body, build_cross_format_openai_chat_upstream_url,
|
||||
build_local_openai_chat_request_body, build_local_openai_chat_upstream_url,
|
||||
};
|
||||
-143
@@ -1,143 +0,0 @@
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::gateway::ai_pipeline::conversion::request::{
|
||||
convert_openai_chat_request_to_claude_request, convert_openai_chat_request_to_gemini_request,
|
||||
convert_openai_chat_request_to_openai_cli_request,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::conversion::{request_conversion_kind, RequestConversionKind};
|
||||
use crate::gateway::provider_transport::{
|
||||
apply_local_body_rules, build_claude_messages_url, build_gemini_content_url,
|
||||
build_openai_chat_url, build_openai_cli_url, build_passthrough_path_url,
|
||||
};
|
||||
|
||||
pub(crate) fn build_local_openai_chat_request_body(
|
||||
body_json: &serde_json::Value,
|
||||
mapped_model: &str,
|
||||
upstream_is_stream: bool,
|
||||
body_rules: Option<&serde_json::Value>,
|
||||
) -> Option<serde_json::Value> {
|
||||
let request_body_object = body_json.as_object()?;
|
||||
let mut provider_request_body = serde_json::Map::from_iter(
|
||||
request_body_object
|
||||
.iter()
|
||||
.map(|(key, value)| (key.clone(), value.clone())),
|
||||
);
|
||||
provider_request_body.insert(
|
||||
"model".to_string(),
|
||||
serde_json::Value::String(mapped_model.to_string()),
|
||||
);
|
||||
if upstream_is_stream {
|
||||
provider_request_body.insert("stream".to_string(), serde_json::Value::Bool(true));
|
||||
}
|
||||
let mut provider_request_body = serde_json::Value::Object(provider_request_body);
|
||||
if !apply_local_body_rules(&mut provider_request_body, body_rules, Some(body_json)) {
|
||||
return None;
|
||||
}
|
||||
Some(provider_request_body)
|
||||
}
|
||||
|
||||
pub(crate) fn build_local_openai_chat_upstream_url(
|
||||
parts: &http::request::Parts,
|
||||
transport: &crate::gateway::provider_transport::GatewayProviderTransportSnapshot,
|
||||
) -> Option<String> {
|
||||
let custom_path = transport
|
||||
.endpoint
|
||||
.custom_path
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty());
|
||||
|
||||
match custom_path {
|
||||
Some(path) => {
|
||||
build_passthrough_path_url(&transport.endpoint.base_url, path, parts.uri.query(), &[])
|
||||
}
|
||||
None => Some(build_openai_chat_url(
|
||||
&transport.endpoint.base_url,
|
||||
parts.uri.query(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build_cross_format_openai_chat_request_body(
|
||||
body_json: &Value,
|
||||
mapped_model: &str,
|
||||
provider_api_format: &str,
|
||||
upstream_is_stream: bool,
|
||||
body_rules: Option<&Value>,
|
||||
) -> Option<Value> {
|
||||
let conversion_kind = request_conversion_kind("openai:chat", provider_api_format)?;
|
||||
let mut provider_request_body = match conversion_kind {
|
||||
RequestConversionKind::ToClaudeStandard => convert_openai_chat_request_to_claude_request(
|
||||
body_json,
|
||||
mapped_model,
|
||||
upstream_is_stream,
|
||||
)?,
|
||||
RequestConversionKind::ToGeminiStandard => convert_openai_chat_request_to_gemini_request(
|
||||
body_json,
|
||||
mapped_model,
|
||||
upstream_is_stream,
|
||||
)?,
|
||||
RequestConversionKind::ToOpenAIFamilyCli => {
|
||||
convert_openai_chat_request_to_openai_cli_request(
|
||||
body_json,
|
||||
mapped_model,
|
||||
upstream_is_stream,
|
||||
false,
|
||||
)?
|
||||
}
|
||||
RequestConversionKind::ToOpenAICompact => {
|
||||
convert_openai_chat_request_to_openai_cli_request(body_json, mapped_model, false, true)?
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
if !apply_local_body_rules(&mut provider_request_body, body_rules, Some(body_json)) {
|
||||
return None;
|
||||
}
|
||||
Some(provider_request_body)
|
||||
}
|
||||
|
||||
pub(crate) fn build_cross_format_openai_chat_upstream_url(
|
||||
parts: &http::request::Parts,
|
||||
transport: &crate::gateway::provider_transport::GatewayProviderTransportSnapshot,
|
||||
mapped_model: &str,
|
||||
provider_api_format: &str,
|
||||
upstream_is_stream: bool,
|
||||
) -> Option<String> {
|
||||
let conversion_kind = request_conversion_kind("openai:chat", provider_api_format)?;
|
||||
let custom_path = transport
|
||||
.endpoint
|
||||
.custom_path
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty());
|
||||
|
||||
match custom_path {
|
||||
Some(path) => {
|
||||
build_passthrough_path_url(&transport.endpoint.base_url, path, parts.uri.query(), &[])
|
||||
}
|
||||
None => match conversion_kind {
|
||||
RequestConversionKind::ToClaudeStandard => Some(build_claude_messages_url(
|
||||
&transport.endpoint.base_url,
|
||||
parts.uri.query(),
|
||||
)),
|
||||
RequestConversionKind::ToGeminiStandard => build_gemini_content_url(
|
||||
&transport.endpoint.base_url,
|
||||
mapped_model,
|
||||
upstream_is_stream,
|
||||
parts.uri.query(),
|
||||
),
|
||||
RequestConversionKind::ToOpenAIFamilyCli => Some(build_openai_cli_url(
|
||||
&transport.endpoint.base_url,
|
||||
parts.uri.query(),
|
||||
false,
|
||||
)),
|
||||
RequestConversionKind::ToOpenAICompact => Some(build_openai_cli_url(
|
||||
&transport.endpoint.base_url,
|
||||
parts.uri.query(),
|
||||
true,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ use super::{
|
||||
GatewayControlSyncDecisionResponse, GatewayError, LocalStreamPlanAndReport,
|
||||
LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::private_surfaces::provider_adaptation_requires_eventstream_accept;
|
||||
use crate::gateway::ai_pipeline::adaptation::surfaces::provider_adaptation_requires_eventstream_accept;
|
||||
use crate::gateway::provider_transport::{
|
||||
build_openai_chat_url, build_openai_cli_url, build_openai_passthrough_headers,
|
||||
ensure_upstream_auth_header,
|
||||
|
||||
+31
-80
@@ -1,29 +1,27 @@
|
||||
use axum::body::Body;
|
||||
use axum::http::Response;
|
||||
|
||||
use serde_json::{Map, Value};
|
||||
use tracing::warn;
|
||||
|
||||
use crate::gateway::{
|
||||
execute_execution_runtime_stream, execute_execution_runtime_sync, AppState,
|
||||
GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
LocalExecutionRuntimeMissDiagnostic,
|
||||
};
|
||||
use crate::gateway::ai_pipeline::planner::{
|
||||
OPENAI_CHAT_STREAM_PLAN_KIND, OPENAI_CHAT_SYNC_PLAN_KIND,
|
||||
};
|
||||
use crate::gateway::{
|
||||
AppState, GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
LocalExecutionRuntimeMissDiagnostic,
|
||||
};
|
||||
|
||||
use crate::gateway::ai_pipeline::planner::standard::openai::{
|
||||
use crate::gateway::ai_pipeline::planner::standard::{
|
||||
convert_openai_chat_request_to_claude_request, convert_openai_chat_request_to_gemini_request,
|
||||
convert_openai_chat_request_to_openai_cli_request, extract_openai_text_content,
|
||||
parse_openai_tool_result_content,
|
||||
};
|
||||
|
||||
#[path = "openai/chat/decision.rs"]
|
||||
mod decision;
|
||||
#[path = "openai/chat/plans.rs"]
|
||||
mod plans;
|
||||
|
||||
use self::decision::{
|
||||
mark_unused_local_openai_chat_candidates, materialize_local_openai_chat_candidate_attempts,
|
||||
materialize_local_openai_chat_candidate_attempts,
|
||||
maybe_build_local_openai_chat_decision_payload_for_candidate, LocalOpenAiChatDecisionInput,
|
||||
};
|
||||
use self::plans::{
|
||||
@@ -33,93 +31,48 @@ use self::plans::{
|
||||
set_local_openai_chat_miss_diagnostic,
|
||||
};
|
||||
|
||||
pub(crate) async fn maybe_execute_sync_via_local_decision(
|
||||
pub(crate) async fn build_local_openai_chat_sync_plan_and_reports_for_kind(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
let plan_and_reports = build_local_openai_chat_sync_plan_and_reports(
|
||||
) -> Result<
|
||||
Vec<crate::gateway::ai_pipeline::planner::plan_builders::LocalSyncPlanAndReport>,
|
||||
GatewayError,
|
||||
> {
|
||||
build_local_openai_chat_sync_plan_and_reports(
|
||||
state, parts, trace_id, decision, body_json, plan_kind,
|
||||
)
|
||||
.await?;
|
||||
if plan_and_reports.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let plan_count = plan_and_reports.len();
|
||||
let mut remaining = plan_and_reports.into_iter();
|
||||
while let Some(plan_and_report) = remaining.next() {
|
||||
if let Some(response) = execute_execution_runtime_sync(
|
||||
state,
|
||||
parts.uri.path(),
|
||||
plan_and_report.plan,
|
||||
trace_id,
|
||||
decision,
|
||||
plan_kind,
|
||||
plan_and_report.report_kind,
|
||||
plan_and_report.report_context,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
mark_unused_local_openai_chat_candidates(state, remaining.collect()).await;
|
||||
return Ok(Some(response));
|
||||
}
|
||||
}
|
||||
|
||||
state.set_local_execution_runtime_miss_diagnostic(
|
||||
trace_id,
|
||||
LocalExecutionRuntimeMissDiagnostic {
|
||||
candidate_count: Some(plan_count),
|
||||
..build_local_openai_chat_miss_diagnostic(
|
||||
decision,
|
||||
plan_kind,
|
||||
body_json.get("model").and_then(|value| value.as_str()),
|
||||
"execution_runtime_candidates_exhausted",
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
Ok(None)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_execute_stream_via_local_decision(
|
||||
pub(crate) async fn build_local_openai_chat_stream_plan_and_reports_for_kind(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
let plan_and_reports = build_local_openai_chat_stream_plan_and_reports(
|
||||
) -> Result<
|
||||
Vec<crate::gateway::ai_pipeline::planner::plan_builders::LocalStreamPlanAndReport>,
|
||||
GatewayError,
|
||||
> {
|
||||
build_local_openai_chat_stream_plan_and_reports(
|
||||
state, parts, trace_id, decision, body_json, plan_kind,
|
||||
)
|
||||
.await?;
|
||||
if plan_and_reports.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let plan_count = plan_and_reports.len();
|
||||
let mut remaining = plan_and_reports.into_iter();
|
||||
while let Some(plan_and_report) = remaining.next() {
|
||||
if let Some(response) = execute_execution_runtime_stream(
|
||||
state,
|
||||
plan_and_report.plan,
|
||||
trace_id,
|
||||
decision,
|
||||
plan_kind,
|
||||
plan_and_report.report_kind,
|
||||
plan_and_report.report_context,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
mark_unused_local_openai_chat_candidates(state, remaining.collect()).await;
|
||||
return Ok(Some(response));
|
||||
}
|
||||
}
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) fn set_local_openai_chat_execution_exhausted_diagnostic(
|
||||
state: &AppState,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
plan_kind: &str,
|
||||
body_json: &serde_json::Value,
|
||||
plan_count: usize,
|
||||
) {
|
||||
state.set_local_execution_runtime_miss_diagnostic(
|
||||
trace_id,
|
||||
LocalExecutionRuntimeMissDiagnostic {
|
||||
@@ -132,8 +85,6 @@ pub(crate) async fn maybe_execute_stream_via_local_decision(
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_build_sync_local_decision_payload(
|
||||
+15
-64
@@ -1,15 +1,17 @@
|
||||
use crate::gateway::ai_pipeline::planner::plan_builders::{
|
||||
LocalStreamPlanAndReport, LocalSyncPlanAndReport,
|
||||
};
|
||||
use crate::gateway::{
|
||||
execute_execution_runtime_stream, execute_execution_runtime_sync, AppState,
|
||||
GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
AppState, GatewayControlDecision, GatewayControlSyncDecisionResponse, GatewayError,
|
||||
};
|
||||
use axum::body::Body;
|
||||
use axum::http::Response;
|
||||
|
||||
#[path = "openai/cli/decision.rs"]
|
||||
mod decision;
|
||||
#[path = "openai/cli/plans.rs"]
|
||||
mod plans;
|
||||
|
||||
use self::decision::{
|
||||
mark_unused_local_openai_cli_candidates, materialize_local_openai_cli_candidate_attempts,
|
||||
materialize_local_openai_cli_candidate_attempts,
|
||||
maybe_build_local_openai_cli_decision_payload_for_candidate,
|
||||
resolve_local_openai_cli_decision_input,
|
||||
};
|
||||
@@ -18,85 +20,34 @@ use self::plans::{
|
||||
resolve_sync_spec,
|
||||
};
|
||||
|
||||
pub(crate) async fn maybe_execute_sync_via_local_openai_cli_decision(
|
||||
pub(crate) async fn build_local_openai_cli_sync_plan_and_reports_for_kind(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
) -> Result<Vec<LocalSyncPlanAndReport>, GatewayError> {
|
||||
let Some(spec) = resolve_sync_spec(plan_kind) else {
|
||||
return Ok(None);
|
||||
return Ok(Vec::new());
|
||||
};
|
||||
|
||||
let plan_and_reports =
|
||||
build_local_sync_plan_and_reports(state, parts, trace_id, decision, body_json, spec)
|
||||
.await?;
|
||||
if plan_and_reports.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut remaining = plan_and_reports.into_iter();
|
||||
while let Some(plan_and_report) = remaining.next() {
|
||||
if let Some(response) = execute_execution_runtime_sync(
|
||||
state,
|
||||
parts.uri.path(),
|
||||
plan_and_report.plan,
|
||||
trace_id,
|
||||
decision,
|
||||
plan_kind,
|
||||
plan_and_report.report_kind,
|
||||
plan_and_report.report_context,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
mark_unused_local_openai_cli_candidates(state, remaining.collect()).await;
|
||||
return Ok(Some(response));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
build_local_sync_plan_and_reports(state, parts, trace_id, decision, body_json, spec).await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_execute_stream_via_local_openai_cli_decision(
|
||||
pub(crate) async fn build_local_openai_cli_stream_plan_and_reports_for_kind(
|
||||
state: &AppState,
|
||||
parts: &http::request::Parts,
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
body_json: &serde_json::Value,
|
||||
plan_kind: &str,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
) -> Result<Vec<LocalStreamPlanAndReport>, GatewayError> {
|
||||
let Some(spec) = resolve_stream_spec(plan_kind) else {
|
||||
return Ok(None);
|
||||
return Ok(Vec::new());
|
||||
};
|
||||
|
||||
let plan_and_reports =
|
||||
build_local_stream_plan_and_reports(state, parts, trace_id, decision, body_json, spec)
|
||||
.await?;
|
||||
if plan_and_reports.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut remaining = plan_and_reports.into_iter();
|
||||
while let Some(plan_and_report) = remaining.next() {
|
||||
if let Some(response) = execute_execution_runtime_stream(
|
||||
state,
|
||||
plan_and_report.plan,
|
||||
trace_id,
|
||||
decision,
|
||||
plan_kind,
|
||||
plan_and_report.report_kind,
|
||||
plan_and_report.report_context,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
mark_unused_local_openai_cli_candidates(state, remaining.collect()).await;
|
||||
return Ok(Some(response));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
build_local_stream_plan_and_reports(state, parts, trace_id, decision, body_json, spec).await
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_build_sync_local_openai_cli_decision_payload(
|
||||
@@ -2,7 +2,7 @@ use aether_contracts::RequestBody;
|
||||
|
||||
use super::augment_sync_report_context;
|
||||
use super::*;
|
||||
use crate::gateway::ai_pipeline::private_surfaces::provider_adaptation_requires_eventstream_accept;
|
||||
use crate::gateway::ai_pipeline::adaptation::surfaces::provider_adaptation_requires_eventstream_accept;
|
||||
use crate::gateway::provider_transport::ensure_upstream_auth_header;
|
||||
|
||||
pub(crate) fn build_standard_sync_plan_from_decision(
|
||||
|
||||
@@ -7,6 +7,7 @@ mod headers;
|
||||
mod policy;
|
||||
mod refresh;
|
||||
mod request;
|
||||
#[path = "../../../adaptation/kiro_stream.rs"]
|
||||
mod stream;
|
||||
mod url;
|
||||
|
||||
|
||||
@@ -36,6 +36,12 @@ pub(crate) use super::super::execution_runtime::{
|
||||
execute_execution_runtime_stream, execute_execution_runtime_sync,
|
||||
execute_execution_runtime_sync_plan,
|
||||
};
|
||||
pub(crate) use super::adaptation::private_envelope::{
|
||||
maybe_build_provider_private_stream_normalizer,
|
||||
maybe_normalize_provider_private_sync_report_payload,
|
||||
normalize_provider_private_report_context, normalize_provider_private_response_value,
|
||||
provider_private_response_allows_sync_finalize, transform_provider_private_stream_line,
|
||||
};
|
||||
pub(crate) use adapters::antigravity::{
|
||||
build_antigravity_safe_v1internal_request, build_antigravity_static_identity_headers,
|
||||
build_antigravity_v1internal_url, classify_local_antigravity_request_support,
|
||||
@@ -67,12 +73,6 @@ pub(crate) use adapters::openai::{
|
||||
build_openai_chat_url, build_openai_cli_url, build_openai_passthrough_headers,
|
||||
resolve_local_openai_chat_auth, supports_local_openai_chat_transport,
|
||||
};
|
||||
pub(crate) use super::private_response::{
|
||||
maybe_build_provider_private_stream_normalizer,
|
||||
maybe_normalize_provider_private_sync_report_payload,
|
||||
normalize_provider_private_report_context, normalize_provider_private_response_value,
|
||||
provider_private_response_allows_sync_finalize, transform_provider_private_stream_line,
|
||||
};
|
||||
pub(crate) use adapters::vertex::{
|
||||
build_vertex_api_key_gemini_content_url, resolve_local_vertex_api_key_query_auth,
|
||||
supports_local_vertex_api_key_gemini_transport_with_network,
|
||||
|
||||
Reference in New Issue
Block a user