objectiveai-sdk 2.0.5

ObjectiveAI SDK, definitions, and utilities
Documentation
use crate::tests::stream_push::stream_push_test;
use super::*;

fn completion(index: u64, error: Option<crate::error::ResponseError>) -> AgentCompletionChunk {
    AgentCompletionChunk {
        index,
        inner: crate::agent::completions::response::streaming::AgentCompletionChunk {
            id: format!("acc-{index}"),
            created: 0,
            messages: vec![],
            object: crate::agent::completions::response::streaming::Object::AgentCompletionChunk,
            usage: None,
            upstream: crate::agent::Upstream::Openrouter,
            error,
            continuation: None,
        },
    }
}

fn chunk_with(
    completions: Vec<AgentCompletionChunk>,
    error: Option<crate::error::ResponseError>,
) -> FunctionInventionChunk {
    FunctionInventionChunk {
        id: "fic-ie".into(),
        completions,
        state: None,
        path: None,
        function: None,
        created: 0,
        object: Object::AlphaScalarFunctionInventionChunk,
        usage: None,
        error,
    }
}

fn err(code: u16, message: &str) -> crate::error::ResponseError {
    crate::error::ResponseError { code, message: message.into() }
}

#[test]
fn inner_errors_empty_completions() {
    let chunk = chunk_with(vec![], None);
    assert!(chunk.inner_errors().next().is_none());
}

#[test]
fn inner_errors_excludes_own_error() {
    let chunk = chunk_with(vec![], Some(err(500, "invention failed")));
    assert!(chunk.inner_errors().next().is_none());
}

#[test]
fn inner_errors_no_completion_errors() {
    let chunk = chunk_with(vec![completion(0, None), completion(1, None)], None);
    assert!(chunk.inner_errors().next().is_none());
}

#[test]
fn inner_errors_mixed() {
    let chunk = chunk_with(
        vec![
            completion(0, None),
            completion(1, Some(err(429, "rate limited"))),
            completion(2, None),
        ],
        None,
    );
    let collected: Vec<_> = chunk.inner_errors().collect();
    assert_eq!(collected.len(), 1);
    assert_eq!(collected[0].agent_completion_index, 1);
    assert_eq!(collected[0].error.code, 429);
    assert_eq!(collected[0].error.message, serde_json::Value::String("rate limited".into()));
}

#[test]
fn inner_errors_all_completions_errored() {
    let chunk = chunk_with(
        vec![
            completion(0, Some(err(500, "a"))),
            completion(1, Some(err(502, "b"))),
            completion(2, Some(err(503, "c"))),
        ],
        None,
    );
    let collected: Vec<_> = chunk.inner_errors().collect();
    assert_eq!(collected.len(), 3);
    assert_eq!(collected[0].agent_completion_index, 0);
    assert_eq!(collected[0].error.code, 500);
    assert_eq!(collected[1].agent_completion_index, 1);
    assert_eq!(collected[1].error.code, 502);
    assert_eq!(collected[2].agent_completion_index, 2);
    assert_eq!(collected[2].error.code, 503);
}

#[test]
fn inner_error_serde_roundtrip() {
    let chunk = chunk_with(vec![completion(9, Some(err(404, "missing")))], None);
    let item = chunk.inner_errors().next().unwrap();
    let wire = serde_json::to_string(&item).unwrap();
    assert_eq!(wire, r#"{"agent_completion_index":9,"error":{"code":404,"message":"missing"}}"#);
    let round: InnerError<'static> = serde_json::from_str(&wire).unwrap();
    assert_eq!(round.agent_completion_index, 9);
    assert_eq!(round.error.code, 404);
    assert_eq!(round.error.message, serde_json::Value::String("missing".into()));
}

stream_push_test!(
    single_chunk_unchanged,
    vec![FunctionInventionChunk {
        id: "fic-1".into(),
        completions: vec![],
        state: None,
        path: None,
        function: None,
        created: 100,
        object: Object::AlphaScalarFunctionInventionChunk,
        usage: None,
        error: None,
    }],
    FunctionInventionChunk {
        id: "fic-1".into(),
        completions: vec![],
        state: None,
        path: None,
        function: None,
        created: 100,
        object: Object::AlphaScalarFunctionInventionChunk,
        usage: None,
        error: None,
    }
);

stream_push_test!(
    completions_merged_by_index,
    vec![
        FunctionInventionChunk {
            id: "fic-2".into(),
            completions: vec![AgentCompletionChunk {
                index: 0,
                inner: crate::agent::completions::response::streaming::AgentCompletionChunk {
                    id: "acc-1".into(),
                    created: 0,
                    messages: vec![],
                    object: crate::agent::completions::response::streaming::Object::AgentCompletionChunk,
                    usage: None,
                    upstream: crate::agent::Upstream::Openrouter,
                    error: None,
                    continuation: None,
                },
            }],
            state: None,
            path: None,
            function: None,
            created: 100,
            object: Object::AlphaScalarFunctionInventionChunk,
            usage: None,
            error: None,
        },
        FunctionInventionChunk {
            id: "fic-2".into(),
            completions: vec![AgentCompletionChunk {
                index: 1,
                inner: crate::agent::completions::response::streaming::AgentCompletionChunk {
                    id: "acc-2".into(),
                    created: 0,
                    messages: vec![],
                    object: crate::agent::completions::response::streaming::Object::AgentCompletionChunk,
                    usage: None,
                    upstream: crate::agent::Upstream::Openrouter,
                    error: None,
                    continuation: None,
                },
            }],
            state: None,
            path: None,
            function: None,
            created: 100,
            object: Object::AlphaScalarFunctionInventionChunk,
            usage: None,
            error: None,
        },
    ],
    FunctionInventionChunk {
        id: "fic-2".into(),
        completions: vec![
            AgentCompletionChunk {
                index: 0,
                inner: crate::agent::completions::response::streaming::AgentCompletionChunk {
                    id: "acc-1".into(),
                    created: 0,
                    messages: vec![],
                    object: crate::agent::completions::response::streaming::Object::AgentCompletionChunk,
                    usage: None,
                    upstream: crate::agent::Upstream::Openrouter,
                    error: None,
                    continuation: None,
                },
            },
            AgentCompletionChunk {
                index: 1,
                inner: crate::agent::completions::response::streaming::AgentCompletionChunk {
                    id: "acc-2".into(),
                    created: 0,
                    messages: vec![],
                    object: crate::agent::completions::response::streaming::Object::AgentCompletionChunk,
                    usage: None,
                    upstream: crate::agent::Upstream::Openrouter,
                    error: None,
                    continuation: None,
                },
            },
        ],
        state: None,
        path: None,
        function: None,
        created: 100,
        object: Object::AlphaScalarFunctionInventionChunk,
        usage: None,
        error: None,
    }
);

stream_push_test!(
    usage_set_from_later_chunk,
    vec![
        FunctionInventionChunk {
            id: "fic-3".into(),
            completions: vec![],
            state: None,
            path: None,
            function: None,
            created: 100,
            object: Object::AlphaVectorFunctionInventionChunk,
            usage: None,
            error: None,
        },
        FunctionInventionChunk {
            id: "fic-3".into(),
            completions: vec![],
            state: None,
            path: None,
            function: None,
            created: 100,
            object: Object::AlphaVectorFunctionInventionChunk,
            usage: Some(crate::agent::completions::response::Usage {
                prompt_tokens: 10,
                completion_tokens: 5,
                total_tokens: 15,
                completion_tokens_details: None,
                prompt_tokens_details: None,
                cost: rust_decimal::Decimal::new(1, 3),
                cost_details: None,
                total_cost: rust_decimal::Decimal::new(1, 3),
            }),
            error: None,
        },
    ],
    FunctionInventionChunk {
        id: "fic-3".into(),
        completions: vec![],
        state: None,
        path: None,
        function: None,
        created: 100,
        object: Object::AlphaVectorFunctionInventionChunk,
        usage: Some(crate::agent::completions::response::Usage {
            prompt_tokens: 10,
            completion_tokens: 5,
            total_tokens: 15,
            completion_tokens_details: None,
            prompt_tokens_details: None,
            cost: rust_decimal::Decimal::new(1, 3),
            cost_details: None,
            total_cost: rust_decimal::Decimal::new(1, 3),
        }),
        error: None,
    }
);

stream_push_test!(
    error_replaced_by_later_chunk,
    vec![
        FunctionInventionChunk {
            id: "fic-4".into(),
            completions: vec![],
            state: None,
            path: None,
            function: None,
            created: 100,
            object: Object::AlphaScalarFunctionInventionChunk,
            usage: None,
            error: Some(crate::error::ResponseError {
                code: 500,
                message: serde_json::json!("first"),
            }),
        },
        FunctionInventionChunk {
            id: "fic-4".into(),
            completions: vec![],
            state: None,
            path: None,
            function: None,
            created: 100,
            object: Object::AlphaScalarFunctionInventionChunk,
            usage: None,
            error: Some(crate::error::ResponseError {
                code: 502,
                message: serde_json::json!("second"),
            }),
        },
    ],
    FunctionInventionChunk {
        id: "fic-4".into(),
        completions: vec![],
        state: None,
        path: None,
        function: None,
        created: 100,
        object: Object::AlphaScalarFunctionInventionChunk,
        usage: None,
        error: Some(crate::error::ResponseError {
            code: 502,
            message: serde_json::json!("second"),
        }),
    }
);

stream_push_test!(
    path_replaced_by_later_chunk,
    vec![
        FunctionInventionChunk {
            id: "fic-5".into(),
            completions: vec![],
            state: None,
            path: Some(crate::RemotePath::Github {
                owner: "owner-a".into(),
                repository: "repo-a".into(),
                commit: "aaa111".into(),
            }),
            function: None,
            created: 100,
            object: Object::AlphaScalarFunctionInventionChunk,
            usage: None,
            error: None,
        },
        FunctionInventionChunk {
            id: "fic-5".into(),
            completions: vec![],
            state: None,
            path: Some(crate::RemotePath::Github {
                owner: "owner-b".into(),
                repository: "repo-b".into(),
                commit: "abc123".into(),
            }),
            function: None,
            created: 100,
            object: Object::AlphaScalarFunctionInventionChunk,
            usage: None,
            error: None,
        },
    ],
    FunctionInventionChunk {
        id: "fic-5".into(),
        completions: vec![],
        state: None,
        path: Some(crate::RemotePath::Github {
            owner: "owner-b".into(),
            repository: "repo-b".into(),
            commit: "abc123".into(),
        }),
        function: None,
        created: 100,
        object: Object::AlphaScalarFunctionInventionChunk,
        usage: None,
        error: None,
    }
);