Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions baml_language/crates/baml_builtins2/baml_std/ai/baml.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[package]
name = "ai"
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ class Journal {
// A journal for one run of a spec, with RunStarted appended.
function new<Out>(spec: FunctionSpec<Out>) -> Journal {
Journal {
log: [
root.events.RunStarted { spec_name: spec.name(), arguments: spec.arguments() },
],
log: [root.events.RunStarted { spec_name: spec.name(), arguments: spec.arguments() }],
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ function _schema_for_signature(handler: baml.AnyFunction) -> map<string, unknown
let _ = props.set(a.name, baml.json.schema(a.type));
required.push(a.name);
}
{
"type": "object",
"properties": props,
"required": required,
"additionalProperties": false,
}
{ "type": "object", "properties": props, "required": required, "additionalProperties": false }
}

// Bound as `ctx` inside a compiler-desugared `@spec` prompt template.
Expand Down
15 changes: 3 additions & 12 deletions baml_language/crates/baml_builtins2/baml_std/ai/ns_mcp/mcp.baml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,7 @@ function _proxy(

// One JSON-RPC message as one line. Pure; tested with literal values.
function rpc_line(id: int?, method: string, params: map<string, unknown>?) -> string {
let m: map<string, unknown> = {
"jsonrpc": "2.0",
"method": method,
};
let m: map<string, unknown> = { "jsonrpc": "2.0", "method": method };
if let i: int = id {
let _ = m.set("id", i);
}
Expand Down Expand Up @@ -73,10 +70,7 @@ class McpConnection {
let init: map<string, unknown> = {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {
"name": "baml-mcp",
"version": "0.1",
},
"clientInfo": { "name": "baml-mcp", "version": "0.1" },
};
let _ = conn._request("initialize", init);
conn._send(rpc_line(null, "notifications/initialized", null));
Expand Down Expand Up @@ -186,10 +180,7 @@ class McpConnection {
// One tools/call. Text content items join as the tool's result; an
// isError result throws, which the runner journals as ToolFailed.
function call_tool(self, name: string, args: map<string, unknown>) -> string {
let params: map<string, unknown> = {
"name": name,
"arguments": args,
};
let params: map<string, unknown> = { "name": name, "arguments": args };
let result = self._request("tools/call", params);
let texts: string[] = [];
for (let item in baml.json.path_or<json[]>(result, ".content", [])) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,16 @@ class TurnMeta {

// The provider's explicit end-of-turn marker. Optional: a stream that simply
// ends (SSE close) also completes the turn.
class TurnDone {}
class TurnDone {
}

type StreamEvent = TextDelta | TurnMeta | TurnDone;

// The single end-of-stream marker returned by both raw turn streams and typed
// function streams. A nominal sentinel is required because null may itself be
// a valid partial value.
class Done {}
class Done {
}

// The raw text-delta stream of ONE model turn. Pull-based: nothing is read
// from the wire until `next()` or `final_turn()` is called.
Expand Down Expand Up @@ -136,7 +138,7 @@ class TurnStream {
function next(self) -> string | Done {
while (true) {
if (self._done) {
return Done {};
return Done { };
}
// deliver decoded events before pulling more from the wire
if (self._pcursor < self._pending.length()) {
Expand All @@ -161,7 +163,7 @@ class TurnStream {
},
let d: TurnDone => {
let _ = self._finish();
return Done {};
return Done { };
},
null => null,
};
Expand All @@ -172,7 +174,7 @@ class TurnStream {
match (sse.next()) {
null => {
let _ = self._finish();
return Done {};
return Done { };
},
let batch: string => {
if let decode: (string) -> StreamEvent[] throws unknown = self._decode {
Expand All @@ -198,7 +200,7 @@ class TurnStream {
},
null => {
let _ = self._finish();
return Done {};
return Done { };
},
}
},
Expand Down Expand Up @@ -249,21 +251,20 @@ class Stream<TStream, TFinal> {
function next(self) -> TStream | Done {
while (true) {
if (self._finished) {
return Done {}
return Done { };
}
match (self._next_text()) {
null => {
self._finished = true;
return Done {}
return Done { };
},
let s: string => {
self._text = self._text + s;
let parsed: TStream | baml.sap.NoYield =
baml.sap.__parse_partial<TStream, TFinal>(self._text, self._cache);
let parsed: TStream | baml.sap.NoYield = baml.sap.__parse_partial<TStream, TFinal>(self._text, self._cache);
match (parsed) {
baml.sap.NoYield => {},
let p: TStream => {
return p
return p;
},
}
},
Expand Down
17 changes: 10 additions & 7 deletions baml_language/crates/baml_builtins2/baml_std/ai/runner.baml
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,19 @@ class Agent<Out> {

// Execute one call: validate, dispatch, append the correlated result.
// A Raise-mode failure throws ToolFailedError after ToolFailed lands.
function _run_one_tool(self, tb: root.tools.Toolbox, call: root.content.ToolUse, j: Journal) -> null {
function _run_one_tool(
self,
tb: root.tools.Toolbox,
call: root.content.ToolUse,
j: Journal,
) -> null {
match (tb.get(call.name)) {
let t: root.tools.Tool => {
let outcome: string? = t.call(call.args) catch_all (e) {
_ => {
j.append_all([root.events.ToolFailed { id: call.id, message: e.to_string() }]);
j.append_all(
[root.events.ToolFailed { id: call.id, message: e.to_string() }],
);
// the per-tool setting wins; null inherits the run's mode
if ((t.on_error ?? self.tool_errors) == root.tools.ErrorMode.Raise) {
let classified = match (e) {
Expand Down Expand Up @@ -253,11 +260,7 @@ class Agent<Out> {
},
};
j.append_all(
[
root.events.FinalProduced {
value_json: baml.json.stringify(value_json),
},
],
[root.events.FinalProduced { value_json: baml.json.stringify(value_json) }],
);
seen = self._emit_from(j, seen);
return RunResult { value: value, journal: j, usage: total };
Expand Down
6 changes: 3 additions & 3 deletions baml_language/crates/baml_builtins2/baml_std/ai/spec.baml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class PromptMessage {
/// prompt into messages and media remains structural until a provider lowers
/// it to its wire format.
class Prompt {
_data $rust_type
_data: $rust_type,

/// Render the prompt as readable text. Message roles are emitted as headers.
//baml:vm
Expand Down Expand Up @@ -47,9 +47,9 @@ function prompt(
) -> baml.TaggedString throws never,
) -> (baml.prompt.Context) -> Prompt throws never {
let render = (ctx: baml.prompt.Context) -> {
let tagged = body(baml.prompt.make_role, ctx)
let tagged = body(baml.prompt.make_role, ctx);
root.internal.assemble_prompt(tagged.parts, tagged.values)
}
};
render
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[package]
name = "anthropic"
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@ function _anthropic_lower_prompt(prompt: ai.Prompt) -> AnthropicPrompt {
system.push(block);
null
} else {
let role = if (message.role == "assistant") { "assistant" } else { "user" };
messages.push(
AnthropicMessage { role: role, tool_results: false, blocks: [block] },
);
let role = if (message.role == "assistant") {
"assistant"
} else {
"user"
};
messages.push(AnthropicMessage { role: role, tool_results: false, blocks: [block] });
null
};
}
Expand Down Expand Up @@ -146,7 +148,9 @@ function _anthropic_lower_journal(j: ai.Journal) -> AnthropicMessage[] {
);
null
},
let c: ai.events.ToolCompleted => _anthropic_push_tool_result(msgs, c.id, c.output, false),
let c: ai.events.ToolCompleted => {
_anthropic_push_tool_result(msgs, c.id, c.output, false)
},
let f: ai.events.ToolFailed => _anthropic_push_tool_result(msgs, f.id, f.message, true),
_ => null,
};
Expand Down Expand Up @@ -193,11 +197,7 @@ function _anthropic_request(
// an otherwise well-formed multi-message prompt.
let first_role = lowered.at(0)?.role ?? "";
if (first_role != "user" && system.length() > 0) {
let first = AnthropicMessage {
role: "user",
tool_results: false,
blocks: system,
};
let first = AnthropicMessage { role: "user", tool_results: false, blocks: system };
let _ = body.set("messages", _anthropic_render_messages([first].concat(lowered)));
null
} else {
Expand Down Expand Up @@ -262,10 +262,7 @@ function _anthropic_stop_reason(s: string) -> ai.content.StopReason {
}

// The one internal entry point: render, send, normalize — one model turn.
function invoke(
c: root.AnthropicClient,
input: ai.ModelTurnInput,
) -> ai.ModelTurn {
function invoke(c: root.AnthropicClient, input: ai.ModelTurnInput) -> ai.ModelTurn {
let req = _anthropic_request(c, input, false);
let resp = ai.wire.send_as<AnthropicResponse>(req, "anthropic");

Expand All @@ -280,7 +277,11 @@ function invoke(
} else if (b.type == "tool_use") {
let empty_args: map<string, unknown> = {};
content.push(
ai.content.ToolUse { id: b.id ?? "", name: b.name ?? "", args: b.input ?? empty_args },
ai.content.ToolUse {
id: b.id ?? "",
name: b.name ?? "",
args: b.input ?? empty_args,
},
);
null
} else {
Expand Down Expand Up @@ -391,7 +392,7 @@ function _anthropic_decode_batch(batch: string) -> ai.stream.StreamEvent[] {
);
null
} else if (t == "message_stop") {
out.push(ai.stream.TurnDone {});
out.push(ai.stream.TurnDone { });
null
} else {
null
Expand All @@ -410,10 +411,7 @@ function _anthropic_decode_batch(batch: string) -> ai.stream.StreamEvent[] {

// The streaming entry point: the same request as `invoke` with
// `stream: true`, wrapped in an ai.TurnStream over the SSE connection.
function invoke_stream(
c: root.AnthropicClient,
input: ai.ModelTurnInput,
) -> ai.stream.TurnStream {
function invoke_stream(c: root.AnthropicClient, input: ai.ModelTurnInput) -> ai.stream.TurnStream {
let req = _anthropic_request(c, input, true);
let sse = baml.http.fetch_sse(req) catch_all (e) {
_ => {
Expand Down
Loading
Loading