Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
c7f3113
chore: update tinyinference bootstrap scheduler
senamakel Oct 19, 2026
69b0c89
Merge pull request #97 from senamakel/epic-8092-246-bootstrap-singlef…
senamakel Oct 19, 2026
e2b18c2
Merge remote-tracking branch 'origin/main' into ta72-oneshot
senamakel Oct 19, 2026
bf5c0ff
test(harness): specify one-shot completion API
senamakel Oct 19, 2026
a3bf391
feat(oneshot): add complete_once and simple_chat helpers
senamakel Oct 19, 2026
68714c0
refactor(harness): avoid cloning one-shot model
senamakel Oct 19, 2026
335e453
fix(harness): simplify oneshot model validation
senamakel Oct 19, 2026
b7c86b8
Merge pull request #99 from senamakel/ta72-oneshot
senamakel Oct 19, 2026
e79860d
feat(harness): add role-keyed turn model assembly
senamakel Oct 19, 2026
cf567d9
feat(harness): complete turn model host integration
senamakel Oct 19, 2026
8ee761d
test(harness): organize turn model host coverage
senamakel Oct 19, 2026
2f82983
test(harness): use stable Claude subprocess fixture
senamakel Oct 19, 2026
a0279a6
test(harness): refresh Claude type debt locations
senamakel Oct 19, 2026
41630e7
Merge pull request #100 from senamakel/ta73-turn-model-set
senamakel Oct 19, 2026
ec76385
feat(router): add cloud fallback role resolution and route source trait
senamakel Oct 19, 2026
84254bd
refactor(router): move behavior tests to mod_tests
senamakel Oct 19, 2026
c827588
refactor(router): clean up router module and tests
senamakel Oct 19, 2026
702f149
refactor(router): simplify default model routing logic
senamakel Oct 19, 2026
896495b
fix(router): suppress fallback diagnostics when explicit default rout…
senamakel Oct 19, 2026
e301bd6
test(router): update test cases for route classification and defaults
senamakel Oct 19, 2026
c37a889
test(router): rename coding role to embeddings in default routing test
senamakel Oct 19, 2026
1424891
Merge pull request #101 from senamakel/epic-8092-a74-workload-router
senamakel Oct 19, 2026
e191fea
feat(harness): enrich generations with resolved routes
senamakel Oct 19, 2026
ab8cbf3
test(harness): use immutable Claude SDK fixture
senamakel Oct 19, 2026
d102dda
Merge pull request #102 from senamakel/epic-8092-a75-resolved-route-e…
senamakel Oct 19, 2026
22e5794
feat(harness): add typed turn stop copy APIs
senamakel Oct 19, 2026
cfc0434
Merge pull request #103 from senamakel/epic-8092-a76-stop-copy
senamakel Oct 19, 2026
b6d9e77
feat(harness): add per-thread reasoning policy
senamakel Oct 19, 2026
0991b72
Merge pull request #104 from senamakel/epic-8092-a77-thread-reasoning
senamakel Oct 19, 2026
8eae434
chore(vendor): bump tinyinference submodule
senamakel Oct 19, 2026
5ef3284
chore(vendor): bump tinyinference submodule
senamakel Oct 19, 2026
6c5f634
chore(deps): add tinyinference-embeddings to lockfile
senamakel Oct 19, 2026
73d62ee
Merge pull request #117 from senamakel/epic-8092-257-inference-pin
senamakel Oct 19, 2026
3227df4
Merge remote-tracking branch 'origin/main' into epic-8092-258-session…
senamakel Oct 20, 2026
b849c51
Merge pull request #146 from senamakel/epic-8092-258-session-context
senamakel Oct 20, 2026
a6f4e3f
chore(vendor): bump tinyinference submodule
senamakel Oct 20, 2026
d271f95
Merge pull request #150 from senamakel/epic-8092-260-managed-auth-typed
senamakel Oct 20, 2026
7f57f78
chore(vendor): bump tinyinference submodule
senamakel Oct 20, 2026
b9b4585
chore(vendor): bump tinyinference submodule
senamakel Oct 20, 2026
fbd3d9f
Merge pull request #152 from senamakel/epic-8092-260-tinyinference-ca…
senamakel Oct 20, 2026
9486485
chore: bump TinyInference observer contract
senamakel Oct 20, 2026
00d848b
Merge pull request #153 from senamakel/epic-8092-260-tinyinference-ob…
senamakel Oct 20, 2026
6f258a0
chore(tinyinference): pin route context-window projection
senamakel Oct 21, 2026
1dad3b6
Merge pull request #156 from senamakel/epic-8092-262-context-window-pin
senamakel Oct 21, 2026
bdac7d8
chore(deps): pin merged tinyinference model defaults
senamakel Oct 21, 2026
c29ab0e
Merge pull request #157 from senamakel/epic-8092-264-ti-pin
senamakel Oct 21, 2026
4212e50
fix(hooks): remove halt truncation reexport
senamakel Oct 21, 2026
93ada1a
Merge commit 'aa64b26a06377e17e1126f355c620318c347798a' into epic-809…
senamakel Oct 21, 2026
50b3fec
Merge pull request #167 from senamakel/epic-8092-halt-owner
senamakel Oct 21, 2026
ba3610b
Merge remote-tracking branch 'fork/epic/8092-inference-out' into epic…
senamakel Oct 21, 2026
0759568
chore: files changed vendor/tinyinference
senamakel Oct 21, 2026
ca099cf
Merge pull request #171 from senamakel/epic-8092-u14-dispatch-admission
senamakel Oct 21, 2026
c1a898f
feat(harness): add controlled one-shot dispatch
senamakel Oct 21, 2026
994e688
Merge pull request #172 from senamakel/leaf-251-oneshot
senamakel Oct 21, 2026
7c62b12
chore(vendor): bump tinyinference submodule
senamakel Oct 21, 2026
109ff7b
chore(vendor): bump tinyinference submodule
senamakel Oct 21, 2026
6fd9ac3
Merge pull request #173 from senamakel/leaf-253-embedding-ti-pin
senamakel Oct 21, 2026
b33ecb8
chore(vendor): bump tinyinference submodule
senamakel Oct 21, 2026
a4f60f0
Merge pull request #174 from senamakel/leaf-256-provider-metadata
senamakel Oct 21, 2026
eea556c
chore(vendor): bump tinyinference submodule
senamakel Oct 22, 2026
583778a
chore(vendor): bump tinyinference submodule
senamakel Oct 22, 2026
5544838
Merge remote-tracking branch 'fork/epic/8092-inference-out' into epic…
senamakel Oct 22, 2026
910c6c5
chore(vendor): bump tinytools submodule
senamakel Oct 22, 2026
23ffece
Merge remote-tracking branch 'origin/main' into epic-8092-owner-curre…
senamakel Oct 22, 2026
1538e9c
fix(deps): align TinyInference 0.5 crate versions
senamakel Oct 22, 2026
e120462
chore: bump tinyinference crates to 0.5.0
senamakel Oct 22, 2026
5308586
fix(claude_code): populate charged_amount_nanos in model response
senamakel Oct 22, 2026
47b15d7
test(cost): add charged_amount_nanos to usage fixtures
senamakel Oct 22, 2026
cfc2162
chore(steering): allow large enum variant on steering command
senamakel Oct 22, 2026
8a9eede
chore(steering): clarify large enum variant allow comment
senamakel Oct 22, 2026
7ed3f3e
Merge pull request #175 from senamakel/epic-8092-owner-current-union
senamakel Oct 22, 2026
3b557cf
refactor(subagents): drop re-export of SubAgentJobRegistry
senamakel Oct 22, 2026
44acf3c
docs(subagents): clarify registry path and tidy test imports
senamakel Oct 22, 2026
b069344
Merge pull request #177 from senamakel/epic-8092-ta-native-subagent-r…
senamakel Oct 22, 2026
004ad00
Merge remote-tracking branch 'origin/main' into epic-8092-final-union…
senamakel Oct 22, 2026
3a52c6c
test(progress): use explicit native progress import
senamakel Oct 22, 2026
2296f03
fix(harness): stop summary role inheriting the primary model pin
senamakel Oct 22, 2026
f27d9f6
test(host): relocate model factory tests to sibling modules
senamakel Oct 22, 2026
850bb18
refactor(host): split model factory into assembly, types, and subproc…
senamakel Oct 22, 2026
f522947
style: tidy imports and test module wiring in model factory
senamakel Oct 22, 2026
da51ac9
chore: update tinyinference review fixes
senamakel Oct 22, 2026
786a8a9
chore(vendor): bump tinyinference submodule
senamakel Oct 22, 2026
debab2c
chore(harness): import ModelBuildGate in subprocess model factory
senamakel Oct 22, 2026
be184f3
refactor(host): inline model build gate doc link
senamakel Oct 22, 2026
fa5ad76
test(router): cover unknown hint default passthrough
senamakel Oct 22, 2026
b3ae15f
feat(host): make model factory request types serializable
senamakel Oct 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ changing the outer transcript or treating a preview as a write.
## Subagent orchestration

`tinyagents-orchestration` owns child-agent composition and the shared
`SubAgentJobRegistry`. The `subagents` feature in `tinyagents-harness-tools`
`tinyagents_orchestration::subagent::SubAgentJobRegistry`. The `subagents`
feature in `tinyagents-harness-tools`
exposes `tinyagents_harness_tools::subagents`, which provides
`DriverSubAgentTool`, the host-planned typed dispatcher: its `background` mode
starts a child and returns a stable job id, while `inline` mode waits for the
Expand Down
2 changes: 1 addition & 1 deletion crates/tinyagents-graph/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ tinyagents-tasks = { path = "../tinyagents-tasks", version = "2.2.0", default-fe
tinyagents-harness = { path = "../tinyagents-harness", version = "2.2.0", default-features = false, features = [
"langfuse",
] }
tinyinference-llm = { path = "../../vendor/tinyinference/crates/tinyinference-llm", version = "0.4.1" }
tinyinference-llm = { path = "../../vendor/tinyinference/crates/tinyinference-llm", version = "0.5.0" }
tinytools = { path = "../../vendor/tinytools/crates/tinytools", version = "0.6.0" }
tokio = { workspace = true, features = ["sync", "time", "macros", "rt", "rt-multi-thread", "fs"] }
tracing = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion crates/tinyagents-harness-tools/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ serde = { workspace = true }
serde_json = { workspace = true }
tinyagents-harness = { path = "../tinyagents-harness", version = "2.2.0", default-features = false }
tinyagents-tasks = { path = "../tinyagents-tasks", version = "2.2.0", default-features = false, optional = true }
tinyinference-llm = { path = "../../vendor/tinyinference/crates/tinyinference-llm", version = "0.4.1", optional = true }
tinyinference-llm = { path = "../../vendor/tinyinference/crates/tinyinference-llm", version = "0.5.0", optional = true }
tinytools = { path = "../../vendor/tinytools/crates/tinytools", version = "0.6.0" }
tinyagents-orchestration = { path = "../tinyagents-orchestration", version = "2.2.0", default-features = false, optional = true }
tokio = { workspace = true, features = ["sync", "time", "macros", "rt", "rt-multi-thread"] }
Expand Down
4 changes: 2 additions & 2 deletions crates/tinyagents-harness-tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ run-state middleware and its required `goals` and `todos` modules.
- `skills` provides `UseSkillTool`, `PackCatalog`, `PackRegistryHandle`, and
`UseSkillDispatch` for binding a selected tool from a named pack.
- `subagents` provides `DriverSubAgentTool`, `SubAgentJobsTool`, and
`SubAgentMessageTool` over the orchestration crate's shared
`SubAgentJobRegistry`.
`SubAgentMessageTool` over the registry owned by
`tinyagents_orchestration::subagent::SubAgentJobRegistry`.
- `thread_locks` provides the public `ThreadLockMap` concurrency primitive.
- The crate root exports `CurrentTimeTool`, `ResolveTimeTool`,
`AskClarificationTool`, `PlanExitTool`, and the `per_call` binding adapter.
Expand Down
1 change: 0 additions & 1 deletion crates/tinyagents-harness-tools/src/subagents/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ mod driver_tool;
mod jobs;

pub use driver_tool::{DriverSubAgentTool, SubagentDriverToolHost};
pub use tinyagents_orchestration::subagent::SubAgentJobRegistry;
#[cfg(test)]
#[path = "driver_tool_tests.rs"]
mod driver_tool_tests;
Expand Down
10 changes: 5 additions & 5 deletions crates/tinyagents-harness-tools/src/subagents/sessions_tests.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::subagents::{SubAgentJobAction, SubAgentJobRegistry, SubAgentJobsTool};
use crate::subagents::{SubAgentJobAction, SubAgentJobsTool};
use std::sync::Arc;
use tinyagents_harness::context::{RunConfig, RunContext};
use tinyagents_harness::ids::new_call_id;
use tinyagents_harness::tool::ToolDispatch;
use tinyagents_orchestration::subagent::*;
use tinyagents_orchestration::subagent::{SubAgentJobRegistry, *};
use tinyagents_tasks::TaskStore;
use tinystoragedrivers_core::{DocumentStore, MemoryStorage, Scope, StorageBackend};

Expand Down Expand Up @@ -213,7 +213,7 @@ async fn jobs_tool_overlays_scoped_sessions_and_awaits_user_envelopes() {
.with_lineage(parent_run.clone(), parent_run.clone()),
)
.unwrap();
let jobs = SubAgentJobsTool::new(crate::subagents::SubAgentJobRegistry::default())
let jobs = SubAgentJobsTool::new(SubAgentJobRegistry::default())
.with_sessions(Arc::new(store.clone()), |owner| owner.to_string())
.with_task_store(task_store, move |_| parent_run.clone());

Expand Down Expand Up @@ -356,7 +356,7 @@ async fn jobs_wait_recovers_terminal_results_from_the_durable_task_store() {
)
.unwrap();

let jobs = SubAgentJobsTool::new(crate::subagents::SubAgentJobRegistry::default())
let jobs = SubAgentJobsTool::new(SubAgentJobRegistry::default())
.with_fixed_action(crate::subagents::SubAgentJobAction::Await)
.with_identifier_fields("task_id", "subagent_session_id")
.with_task_store(task_store.clone(), move |_| owner.clone())
Expand Down Expand Up @@ -410,7 +410,7 @@ async fn jobs_wait_recovers_terminal_results_from_the_durable_task_store() {
assert_eq!(failed["error"], "durable failure");
assert_eq!(failed["agent"], "reviewer");

let foreign_jobs = SubAgentJobsTool::new(crate::subagents::SubAgentJobRegistry::default())
let foreign_jobs = SubAgentJobsTool::new(SubAgentJobRegistry::default())
.with_fixed_action(crate::subagents::SubAgentJobAction::Await)
.with_identifier_field("task_id")
.with_task_store(task_store.clone(), |_| {
Expand Down
11 changes: 6 additions & 5 deletions crates/tinyagents-harness/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ thiserror = "2"
tracing = { workspace = true }
tinyagents-definition = { path = "../tinyagents-definition", version = "2.2.0" }
tinytools-agent = { path = "../../vendor/tinytools/crates/tinytools-agent", version = "0.6.0", default-features = false }
tinyinference-llm = { path = "../../vendor/tinyinference/crates/tinyinference-llm", version = "0.4.1" }
tinyinference-core = { path = "../../vendor/tinyinference/crates/tinyinference-core", version = "0.4.1" }
tinyinference-embeddings = { path = "../../vendor/tinyinference/crates/tinyinference-embeddings", version = "0.4.1" }
tinyinference-image = { path = "../../vendor/tinyinference/crates/tinyinference-image", version = "0.4.1", optional = true }
tinyinference-video = { path = "../../vendor/tinyinference/crates/tinyinference-video", version = "0.4.1", optional = true }
tinyinference-llm = { path = "../../vendor/tinyinference/crates/tinyinference-llm", version = "0.5.0" }
tinyinference-providers = { path = "../../vendor/tinyinference/crates/tinyinference-providers", version = "0.5.0" }
tinyinference-core = { path = "../../vendor/tinyinference/crates/tinyinference-core", version = "0.5.0" }
tinyinference-embeddings = { path = "../../vendor/tinyinference/crates/tinyinference-embeddings", version = "0.5.0" }
tinyinference-image = { path = "../../vendor/tinyinference/crates/tinyinference-image", version = "0.5.0", optional = true }
tinyinference-video = { path = "../../vendor/tinyinference/crates/tinyinference-video", version = "0.5.0", optional = true }
tinytools = { path = "../../vendor/tinytools/crates/tinytools", version = "0.6.0" }
# Shared URL admission for opt-in remote multimodal attachments.
tinytools-std = { path = "../../vendor/tinytools/crates/tinytools-std", version = "0.6.0", optional = true }
Expand Down
58 changes: 58 additions & 0 deletions crates/tinyagents-harness/src/agent_loop/mod_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9121,6 +9121,64 @@ async fn request_reasoning_wins_over_the_run_policy_default() {
);
}

#[tokio::test]
async fn thread_reasoning_snapshot_flows_through_policy_and_request_override_wins() {
use crate::testkit::ScriptedModel;

let store = crate::thread_reasoning::ThreadReasoningStore::default();
let thread = crate::ids::ThreadId::new("conversation-a");
store.set_effort(&thread, ReasoningEffort::High);
let turn_snapshot = store.reasoning_for_turn(Some(&thread), Some(4_000));
store.set_effort(&thread, ReasoningEffort::Low);

let model = Arc::new(ScriptedModel::replies(vec!["first", "second", "third"]));
let mut harness: AgentHarness<()> = AgentHarness::new();
harness.register_model("mock", model.clone());
harness.with_policy(RunPolicy {
default_reasoning: turn_snapshot,
..RunPolicy::default()
});

harness
.invoke_default(&(), vec![Message::user("first turn")])
.await
.expect("first run succeeds");

let requests = model.requests();
let first = requests.first().expect("first model call");
let reasoning = first.reasoning.as_ref().expect("reasoning configured");
assert_eq!(reasoning.effort, Some(ReasoningEffort::High));
assert_eq!(reasoning.budget_tokens, Some(2_200));

harness.with_policy(RunPolicy {
default_reasoning: store.reasoning_for_turn(Some(&thread), Some(4_000)),
..RunPolicy::default()
});
harness
.invoke_default(&(), vec![Message::user("next turn")])
.await
.expect("next run succeeds");
let requests = model.requests();
let next_reasoning = requests[1]
.reasoning
.as_ref()
.expect("reasoning configured");
assert_eq!(next_reasoning.effort, Some(ReasoningEffort::Low));

harness.push_middleware(Arc::new(RequestReasoningEffort(ReasoningEffort::XHigh)));
harness
.invoke_default(&(), vec![Message::user("request override")])
.await
.expect("request override run succeeds");
let requests = model.requests();
let reasoning = requests[2]
.reasoning
.as_ref()
.expect("request reasoning configured");
assert_eq!(reasoning.effort, Some(ReasoningEffort::XHigh));
assert_eq!(reasoning.budget_tokens, None);
}

// ── wave 1 follow-ups: batch termination and mixed truncated turns ───────────

#[tokio::test]
Expand Down
3 changes: 3 additions & 0 deletions crates/tinyagents-harness/src/cost/mod_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ fn estimates_each_component() {
cache_creation_tokens: 200,
reasoning_tokens: 10,
charged_amount: None,
charged_amount_nanos: None,
context_window_tokens: None,
};
let cost = estimate_cost(&pricing(), &usage);
Expand Down Expand Up @@ -243,6 +244,7 @@ fn cache_and_reasoning_tokens_are_not_double_counted() {
cache_creation_tokens: 0,
reasoning_tokens: 0,
charged_amount: None,
charged_amount_nanos: None,
context_window_tokens: None,
};
let cost = estimate_cost(&pricing(), &usage);
Expand Down Expand Up @@ -328,6 +330,7 @@ fn tiered_pricing_falls_back_to_flat_rate_for_unset_tier_fields() {
cache_creation_tokens: 0,
reasoning_tokens: 0,
charged_amount: None,
charged_amount_nanos: None,
context_window_tokens: None,
};
let cost = estimate_cost(&pricing, &usage);
Expand Down
1 change: 1 addition & 0 deletions crates/tinyagents-harness/src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub mod ordered_sender;
pub use call_dedupe::{CallDedupe, IterationCursor, advance_iteration};
pub use cap_pauser::{CapPauser, PauseRecorder};
pub use compaction_log::log_compacted;
pub(crate) use generation_enrichment::is_valid_provider_id;
pub use generation_enrichment::{GenerationEnrichment, GenerationPricing};
pub use ordered_sender::{DEFAULT_MAX_OVERFLOW, OrderedSender, SendFailure};
pub use types::*;
Expand Down
16 changes: 13 additions & 3 deletions crates/tinyagents-harness/src/host/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ embedding, not as a way to fake "unconfigured."
| `ContextComposer`, `StaticContextComposer`, `TurnContextRequest` | `context_composer` | Builds a turn's system prompt and preamble (required). |
| `SecurityGate`, `AllowAllSecurityGate`, `GateDecision`, `ScreenOutcome`, `ToolCallRequest`, `ContentOrigin` | `security_gate` | Authorizes tool calls, screens untrusted text (required). |
| `ModelResolver<State>`, `FixedModelResolver`, `PrebuiltModelResolver`, `ModelResolveRequest` | `model_resolver` | Chooses the model for a turn (required). |
| `ModelFactory<State>`, `ModelBuildGate`, `ModelBuildRequest`, `BuildOpts`, `ModelPurpose`, `TurnModelSet` | `model_factory` | Builds role-keyed primary, workload, and summarization models with host policy checks. See [`model_factory/README.md`](model_factory/README.md) for assembly and provider boundaries. |
| `AgentMemory`, `InMemoryAgentMemory`, `MemoryId`, `MemoryItem`, `NewMemory`, `RecallRequest` | `agent_memory` | Durable user memory (optional). |
| `BudgetGate`, `UnlimitedBudgetGate`, `Permit`, `CallEstimate`, `ContextState`, `CompressionHint` | `budget_gate` | Admission, spend accounting, compression advice (optional). |
| `ProgressSink`, `NoopProgressSink`, `RecordingProgressSink`, `ProgressEvent` | `progress_sink` | Coarse turn progress for a UI (optional). |
Expand All @@ -67,6 +68,7 @@ embedding, not as a way to fake "unconfigured."
| `context_composer.rs` | `ContextComposer` trait, `TurnContextRequest`, `StaticContextComposer`. |
| `experience_store.rs` | `ExperienceStore` trait, `Experience`, `InMemoryExperienceStore`. |
| `learning_sink.rs` | `LearningSink` trait, `TurnSummary`, `NoopLearningSink`. |
| `model_factory.rs` and `model_factory/` | Thin re-export plus the model-factory module; see its [module README](model_factory/README.md) for file ownership and operational constraints. |
| `model_resolver.rs` | `ModelResolver<State>` trait, `ModelResolveRequest`, `FixedModelResolver`, and `PrebuiltModelResolver` for lead/pin/hint routes. |
| `progress_sink.rs` | `ProgressEvent`, `ProgressSink` trait, `NoopProgressSink`, `RecordingProgressSink`. |
| `security_gate.rs` | `SecurityGate` trait, `ToolCallRequest`, `GateDecision`, `ScreenOutcome`, `ContentOrigin`. |
Expand Down Expand Up @@ -112,6 +114,14 @@ composed transcript, and a security-authorized tool set, which is what keeps
the loop reusable for both hosted and unhosted (explicit-model) callers.

ModelResolveRequest carries model_hint separately from model_pin. Hints are
host-interpreted routing vocabulary; pins are concrete model identifiers.
Definition hints reach every hosted provider resolution, unless an exact model
override is present. Missing hints in older serialized requests remain None.
host-interpreted routing vocabulary. A construction-time model pin may be a
requested alias; `ResolvedModelRoute` records the concrete provider and model
the host selected.

`ModelBuildRequest` is a construction-time request. Hosts gate each request
before factory construction, then can use `TurnModelSet::map_models` to apply a
per-turn wrapper to every built model before obtaining an owned resolver,
ordered registrations, or summarizer. Models and resolvers obtained before
mapping retain the earlier model instances. Definition hints reach every
hosted provider resolution, unless an exact model override is present. Missing
hints in older serialized requests remain None.
5 changes: 5 additions & 0 deletions crates/tinyagents-harness/src/host/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub mod budget_gate;
pub mod context_composer;
pub mod experience_store;
pub mod learning_sink;
pub mod model_factory;
pub mod model_resolver;
pub mod progress_sink;
pub mod security_gate;
Expand All @@ -56,6 +57,10 @@ pub use experience_store::{Experience, ExperienceStore, InMemoryExperienceStore}
pub use learning_sink::{
LearningSink, NoopLearningSink, ToolOutcomeRecord, TurnSummary, classify_tool_failure,
};
pub use model_factory::{
BuildOpts, ModelBuildGate, ModelBuildRequest, ModelFactory, ModelPurpose, TurnModelSet,
TurnModelSetBuilder,
};
pub use model_resolver::{
FixedModelResolver, ModelResolveRequest, ModelResolver, PrebuiltModelResolver,
};
Expand Down
16 changes: 16 additions & 0 deletions crates/tinyagents-harness/src/host/model_factory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! Host-facing model construction API, split into request types, turn assembly,
//! and provider-specific subprocess adapters.

mod assembly;
mod types;

#[cfg(feature = "claude-code")]
mod subprocess;

pub use assembly::{TurnModelSet, TurnModelSetBuilder};
pub use types::{BuildOpts, ModelBuildGate, ModelBuildRequest, ModelFactory, ModelPurpose};

#[cfg(feature = "claude-code")]
pub use subprocess::{
SubprocessProviderContext, build_claude_subprocess_model, build_claude_subprocess_model_with,
};
36 changes: 36 additions & 0 deletions crates/tinyagents-harness/src/host/model_factory/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Host model factory

This module assembles a turn's primary model, optional workload-tier models,
and summarizer from host-owned construction policy. It keeps provider
selection and authorization at the host boundary while giving the harness a
stable description of each requested route.

## Public surface

`types.rs` defines the serde-compatible `BuildOpts`, `ModelPurpose`, and
`ModelBuildRequest` values, plus the `ModelBuildGate` and `ModelFactory`
contracts. Hosts implement the gate to authorize each construction request and
the factory to return a model with its resolved provider/model route.

`assembly.rs` owns `TurnModelSetBuilder` and `TurnModelSet`. It builds the
primary route, independently builds workload tiers (omitting unavailable or
gated tiers), builds the summarizer, and records the concrete routes and error
slots for later resolution. A primary pin does not implicitly pin workload
routes. An explicit summarization role with no summary pin uses that role's
configured default.

`subprocess.rs` adapts Claude Code and Claude Agent SDK route values to the
existing provider implementations. Hosts must run `ModelBuildGate` before
constructing these subprocess-backed models. The injected constructor supports
tests and hosts that own credential or process setup themselves.

## Operational constraints

- This module describes construction requests; it does not own product
configuration, credentials, or provider policy.
- Workload failures are omitted from the turn model set; primary and
summarization construction failures are returned to the host.
- Route aliases and concrete provider/model identities remain distinct. Use
`ResolvedModelRoute` for the concrete result.
- Keep value types limited to serde and standard-library data so hosts can
persist or transport requests without importing runtime-specific types.
Loading
Loading