Skip to main content

Documentation Index

Fetch the complete documentation index at: https://cognis.vasanth.xyz/llms.txt

Use this file to discover all available pages before exploring further.

cognis-macros is the proc-macro crate. It exists so the rest of the workspace can use derives without dragging proc-macro infrastructure into every dependency. You don’t normally depend on this directly — cognis-core re-exports the derives, and cognis re-exports them through that.

Crate metadata

FieldValue
Latest version0.3
docs.rsdocs.rs/cognis-macros
Repo pathcrates/cognis-macros

#[cognis::tool]

Attribute macro that turns an async fn into an Arc<dyn Tool>-producing function.
use cognis_core::schemars::{self, JsonSchema};
use serde::Deserialize;

#[derive(Deserialize, JsonSchema)]
struct GetWeatherArgs {
    /// City to look up.
    city: String,
}

#[cognis::tool(
    name = "get_weather",
    description = "Look up current weather for a city.",
    return_direct = false,
)]
async fn get_weather(args: GetWeatherArgs) -> cognis::Result<String> {
    Ok(format!("It's 22°C in {}.", args.city))
}
Attributes:
AttributeDefaultEffect
name = "..."fn nameTool name as the model sees it.
description = "..."fn doc-commentDescription as the model sees it.
return_direct = true/falsefalseIf true, the tool’s output becomes the final response (skip the next model turn).
crate_path = "..."cognis_coreOverride for renamed re-export paths.
Schema validators on fn arguments:
AttributeEffect
#[schema(range(min = 0, max = 100))]Numeric bounds.
#[schema(length(min = 1, max = 200))]String / Vec length.
#[schema(pattern("regex"))]Regex.
#[schema(enum_values("low", "medium", "high"))]Enum.
#[schema(format("email"))]JSON Schema format.
These emit both runtime validation and #[schemars(...)] annotations on the generated args struct, so the model sees them in the JSON Schema. The macro can also wrap an impl block containing exactly one #[tool]-marked async method — useful when the tool struct holds shared config (HTTP client, DB pool):
struct MyTool {
    client: reqwest::Client,
}

impl MyTool {
    #[cognis::tool(name = "fetch", description = "GET a URL.")]
    async fn fetch(&self, args: FetchArgs) -> cognis::Result<String> {
        // self.client.get(args.url).send().await…
        todo!()
    }
}

#[derive(GraphStateV2)]

Generates a sibling <Name>Update struct and an impl GraphState for <Name> from a state struct annotated with per-field #[reducer(...)] attributes.
use cognis::prelude::*;

#[derive(Default, Clone, Debug, GraphStateV2)]
struct MyState {
    #[reducer(append)]   messages: Vec<Message>,
    #[reducer(add)]      counter: u32,
    #[reducer(merge)]    metadata: serde_json::Value,
    // unannotated → last_value
    pending: Option<ToolCall>,
}
Reducer options:
#[reducer(...)]Behavior
last_value (default)self.field = update.field
appendself.field.extend(update.field)
addself.field += update.field
mergedeep-merge JSON
The macro produces:
  • A struct MyStateUpdate mirroring the fields.
  • impl GraphState for MyState { type Update = MyStateUpdate; fn apply(&mut self, u: MyStateUpdate) { /* per reducer */ } }.
#[derive(GraphState)] is the older, slightly different shape; new code should use GraphStateV2.

When to import directly

You usually shouldn’t. The derives are re-exported through cognis_core (and through the umbrella cognis::prelude), so:
use cognis::prelude::*;  // GraphStateV2 derive in scope

// or, for #[cognis::tool], use the path-qualified form:
#[cognis::tool(name = "foo", description = "…")]
async fn foo(/* … */) { /* … */ }
If you have your own crate that vends the derives under a different path, set crate_path = "your_crate" on the tool macro.

See also

Tools

User guide for #[cognis::tool].

Graph state

User guide for GraphStateV2.