Support Linux refactoring checks
This commit is contained in:
@@ -1173,7 +1173,7 @@ pub(crate) fn parse_tool_calls(
|
||||
let (content, calls) = if model == ModelChoice::Glm52 {
|
||||
parse_glm_calls(text)?
|
||||
} else {
|
||||
crate::server::parse_dsml_tool_calls(text)?
|
||||
crate::dsml::parse_tool_calls(text)?
|
||||
};
|
||||
calls
|
||||
.into_iter()
|
||||
|
||||
15
src/app.rs
15
src/app.rs
@@ -19,7 +19,7 @@ use crate::config::{
|
||||
GitDiffWhitespace,
|
||||
};
|
||||
use crate::database::{Database, ProjectWithSessions, SessionState, StoredMessage};
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
use crate::engine::ChatTurn;
|
||||
use crate::metrics::{KvCacheReport, Metrics, MetricsSnapshot};
|
||||
use crate::model::{self, DownloadOutcome, DownloadProgress, ManagedArtifactId, ModelChoice};
|
||||
@@ -36,9 +36,11 @@ use rfd::AsyncFileDialog;
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use std::sync::mpsc::{self, TryRecvError};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
#[cfg(target_os = "macos")]
|
||||
use std::sync::{Mutex, RwLock};
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
@@ -595,6 +597,7 @@ impl App {
|
||||
active_generation: None,
|
||||
#[cfg(target_os = "macos")]
|
||||
active_compaction: None,
|
||||
#[cfg(target_os = "macos")]
|
||||
active_tool_check: None,
|
||||
#[cfg(target_os = "macos")]
|
||||
agent_tools: None,
|
||||
@@ -737,6 +740,7 @@ impl App {
|
||||
active_generation: None,
|
||||
#[cfg(target_os = "macos")]
|
||||
active_compaction: None,
|
||||
#[cfg(target_os = "macos")]
|
||||
active_tool_check: None,
|
||||
#[cfg(target_os = "macos")]
|
||||
agent_tools: None,
|
||||
@@ -1567,10 +1571,13 @@ impl App {
|
||||
self.error = Some(format!("Could not play media: {error}"));
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
let _ = (title, video);
|
||||
if let Err(error) = std::process::Command::new("open").arg(url).spawn() {
|
||||
self.error = Some(format!("Could not open media: {error}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::RequestA2uiDismiss(surface_id) => {
|
||||
if self.generating {
|
||||
self.error = Some(
|
||||
@@ -1788,8 +1795,10 @@ impl App {
|
||||
if let Some(database) = &mut self.database {
|
||||
match database.delete_project(project_id) {
|
||||
Ok(()) => {
|
||||
for session_id in checkpoint_ids {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let _ = checkpoint_ids;
|
||||
#[cfg(target_os = "macos")]
|
||||
for session_id in checkpoint_ids {
|
||||
self.background_chats.remove(&session_id);
|
||||
}
|
||||
self.drafts.remove(&project_id);
|
||||
|
||||
@@ -293,7 +293,7 @@ fn sync_a2ui_message(
|
||||
renderable_surface_updated
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
fn chat_turn(message: &ChatMessage) -> ChatTurn {
|
||||
ChatTurn {
|
||||
user: message.user,
|
||||
@@ -368,7 +368,7 @@ fn project_agents(path: &Path) -> Result<Option<String>, String> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
fn title_context(messages: impl IntoIterator<Item = ChatTurn>) -> Vec<ChatTurn> {
|
||||
let mut started = false;
|
||||
messages
|
||||
@@ -497,6 +497,8 @@ impl App {
|
||||
#[cfg(target_os = "macos")]
|
||||
let agents =
|
||||
agents_prompt_for_turn(opening_turn, opening_agents, self.session_agents_prompt());
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let agents = None::<String>;
|
||||
self.a2ui_auto_switch_pending = true;
|
||||
self.context_notice = None;
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -535,6 +537,7 @@ impl App {
|
||||
&effective.turn.system_prompt,
|
||||
self.compaction_summary(),
|
||||
);
|
||||
#[cfg(target_os = "macos")]
|
||||
let assistant_reasoning = effective.turn.reasoning_mode != ReasoningMode::Direct;
|
||||
#[cfg(target_os = "macos")]
|
||||
let model_prompt = if self.config.a2ui_enabled {
|
||||
@@ -700,7 +703,6 @@ impl App {
|
||||
{
|
||||
let _ = effective;
|
||||
self.error = Some("Local Metal generation requires macOS.".into());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::*;
|
||||
use std::sync::RwLock;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(super) struct PreferenceDraft {
|
||||
@@ -437,6 +438,7 @@ impl App {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
let dev_brain_changed = self.config.dev_brain != config.dev_brain;
|
||||
#[cfg(target_os = "macos")]
|
||||
let endpoint_changed = self.config.endpoint != config.endpoint;
|
||||
@@ -447,6 +449,7 @@ impl App {
|
||||
{
|
||||
self._endpoint = None;
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
let pending_endpoint =
|
||||
if config.endpoint.enabled && (endpoint_changed || self._endpoint.is_none()) {
|
||||
let Some(generation) = &self.generation_service else {
|
||||
|
||||
210
src/dsml.rs
Normal file
210
src/dsml.rs
Normal file
@@ -0,0 +1,210 @@
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) struct Syntax {
|
||||
pub(crate) tool_start: &'static str,
|
||||
pub(crate) tool_end: &'static str,
|
||||
pub(crate) invoke_start: &'static str,
|
||||
pub(crate) invoke_end: &'static str,
|
||||
pub(crate) parameter_start: &'static str,
|
||||
pub(crate) parameter_end: &'static str,
|
||||
}
|
||||
|
||||
pub(crate) const SYNTAXES: [Syntax; 3] = [
|
||||
Syntax {
|
||||
tool_start: "<|DSML|tool_calls>",
|
||||
tool_end: "</|DSML|tool_calls>",
|
||||
invoke_start: "<|DSML|invoke",
|
||||
invoke_end: "</|DSML|invoke>",
|
||||
parameter_start: "<|DSML|parameter",
|
||||
parameter_end: "</|DSML|parameter>",
|
||||
},
|
||||
Syntax {
|
||||
tool_start: "<DSML|tool_calls>",
|
||||
tool_end: "</DSML|tool_calls>",
|
||||
invoke_start: "<DSML|invoke",
|
||||
invoke_end: "</DSML|invoke>",
|
||||
parameter_start: "<DSML|parameter",
|
||||
parameter_end: "</DSML|parameter>",
|
||||
},
|
||||
Syntax {
|
||||
tool_start: "<tool_calls>",
|
||||
tool_end: "</tool_calls>",
|
||||
invoke_start: "<invoke",
|
||||
invoke_end: "</invoke>",
|
||||
parameter_start: "<parameter",
|
||||
parameter_end: "</parameter>",
|
||||
},
|
||||
];
|
||||
|
||||
pub(crate) fn parse_tool_calls(text: &str) -> Result<(String, Vec<(String, Value)>), String> {
|
||||
let Some((start, syntax)) = SYNTAXES
|
||||
.iter()
|
||||
.filter_map(|syntax| text.find(syntax.tool_start).map(|start| (start, *syntax)))
|
||||
.min_by_key(|(start, _)| *start)
|
||||
else {
|
||||
return Ok((text.to_owned(), Vec::new()));
|
||||
};
|
||||
let Some(relative_end) = text[start..].find(syntax.tool_end) else {
|
||||
return Err("invalid or incomplete DSML tool call".into());
|
||||
};
|
||||
let end = start + relative_end + syntax.tool_end.len();
|
||||
let content = text[..start].trim_end().to_owned();
|
||||
let raw = &text[start..end];
|
||||
let mut cursor = syntax.tool_start.len();
|
||||
let mut calls = Vec::new();
|
||||
loop {
|
||||
skip_whitespace(raw, &mut cursor);
|
||||
if raw[cursor..].starts_with(syntax.tool_end) {
|
||||
break;
|
||||
}
|
||||
if !raw[cursor..].starts_with(syntax.invoke_start) {
|
||||
return Err("invalid or incomplete DSML tool call".into());
|
||||
}
|
||||
let tag_end = raw[cursor..]
|
||||
.find('>')
|
||||
.map(|offset| cursor + offset + 1)
|
||||
.ok_or_else(|| "invalid or incomplete DSML tool call".to_owned())?;
|
||||
let name = attribute(&raw[cursor..tag_end], "name")
|
||||
.ok_or_else(|| "invalid or incomplete DSML tool call".to_owned())?;
|
||||
cursor = tag_end;
|
||||
let mut arguments = Map::new();
|
||||
loop {
|
||||
skip_whitespace(raw, &mut cursor);
|
||||
if raw[cursor..].starts_with(syntax.invoke_end) {
|
||||
cursor += syntax.invoke_end.len();
|
||||
break;
|
||||
}
|
||||
let (name, value) = parse_parameter(raw, &mut cursor, syntax)?
|
||||
.ok_or_else(|| "invalid or incomplete DSML tool call".to_owned())?;
|
||||
arguments.insert(name, value);
|
||||
}
|
||||
calls.push((name, Value::Object(arguments)));
|
||||
}
|
||||
if calls.is_empty() {
|
||||
return Err("invalid or incomplete DSML tool call".into());
|
||||
}
|
||||
Ok((content, calls))
|
||||
}
|
||||
|
||||
fn parse_parameter(
|
||||
text: &str,
|
||||
cursor: &mut usize,
|
||||
syntax: Syntax,
|
||||
) -> Result<Option<(String, Value)>, String> {
|
||||
if !text[*cursor..].starts_with(syntax.parameter_start) {
|
||||
return Ok(None);
|
||||
}
|
||||
let Some(tag_end) = text[*cursor..].find('>').map(|end| *cursor + end + 1) else {
|
||||
return Ok(None);
|
||||
};
|
||||
let tag = &text[*cursor..tag_end];
|
||||
let Some(name) = attribute(tag, "name") else {
|
||||
return Ok(None);
|
||||
};
|
||||
let is_string = attribute(tag, "string");
|
||||
*cursor = tag_end;
|
||||
let mut nested_start = *cursor;
|
||||
skip_whitespace(text, &mut nested_start);
|
||||
if is_string.is_none() && text[nested_start..].starts_with(syntax.parameter_start) {
|
||||
*cursor = nested_start;
|
||||
let mut nested = Map::new();
|
||||
loop {
|
||||
skip_whitespace(text, cursor);
|
||||
if !text[*cursor..].starts_with(syntax.parameter_start) {
|
||||
break;
|
||||
}
|
||||
let Some((name, value)) = parse_parameter(text, cursor, syntax)? else {
|
||||
return Ok(None);
|
||||
};
|
||||
nested.insert(name, value);
|
||||
}
|
||||
skip_whitespace(text, cursor);
|
||||
if !text[*cursor..].starts_with(syntax.parameter_end) {
|
||||
return Ok(None);
|
||||
}
|
||||
*cursor += syntax.parameter_end.len();
|
||||
return Ok(Some((name, Value::Object(nested))));
|
||||
}
|
||||
let Some(value_end) = text[*cursor..]
|
||||
.find(syntax.parameter_end)
|
||||
.map(|end| *cursor + end)
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
let raw = &text[*cursor..value_end];
|
||||
*cursor = value_end + syntax.parameter_end.len();
|
||||
let value = if is_string.as_deref().unwrap_or("true") == "true" {
|
||||
Value::String(unescape(raw))
|
||||
} else {
|
||||
serde_json::from_str(raw)
|
||||
.map_err(|error| format!("invalid DSML tool arguments: {error}"))?
|
||||
};
|
||||
Ok(Some((name, value)))
|
||||
}
|
||||
|
||||
fn attribute(tag: &str, name: &str) -> Option<String> {
|
||||
let start = tag.find(&format!("{name}=\""))? + name.len() + 2;
|
||||
let end = start + tag[start..].find('"')?;
|
||||
Some(unescape(&tag[start..end]))
|
||||
}
|
||||
|
||||
fn skip_whitespace(text: &str, cursor: &mut usize) {
|
||||
while text[*cursor..]
|
||||
.chars()
|
||||
.next()
|
||||
.is_some_and(char::is_whitespace)
|
||||
{
|
||||
*cursor += text[*cursor..].chars().next().unwrap().len_utf8();
|
||||
}
|
||||
}
|
||||
|
||||
fn unescape(text: &str) -> String {
|
||||
text.replace(""", "\"")
|
||||
.replace(">", ">")
|
||||
.replace("<", "<")
|
||||
.replace("&", "&")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parses_reference_and_legacy_dsml_syntaxes() {
|
||||
for (start, end, invoke, invoke_end, parameter, parameter_end) in [
|
||||
(
|
||||
"<|DSML|tool_calls>",
|
||||
"</|DSML|tool_calls>",
|
||||
"<|DSML|invoke",
|
||||
"</|DSML|invoke>",
|
||||
"<|DSML|parameter",
|
||||
"</|DSML|parameter>",
|
||||
),
|
||||
(
|
||||
"<DSML|tool_calls>",
|
||||
"</DSML|tool_calls>",
|
||||
"<DSML|invoke",
|
||||
"</DSML|invoke>",
|
||||
"<DSML|parameter",
|
||||
"</DSML|parameter>",
|
||||
),
|
||||
(
|
||||
"<tool_calls>",
|
||||
"</tool_calls>",
|
||||
"<invoke",
|
||||
"</invoke>",
|
||||
"<parameter",
|
||||
"</parameter>",
|
||||
),
|
||||
] {
|
||||
let raw = format!(
|
||||
"done{start}{invoke} name=\"read\">{parameter} name=\"path\" string=\"true\">src/main.rs{parameter_end}{invoke_end}{end}"
|
||||
);
|
||||
let (content, calls) = parse_tool_calls(&raw).unwrap();
|
||||
assert_eq!(content, "done");
|
||||
assert_eq!(calls[0].0, "read");
|
||||
assert_eq!(calls[0].1["path"], "src/main.rs");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
mod gguf;
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
mod kvstore;
|
||||
#[cfg(target_os = "macos")]
|
||||
mod metal;
|
||||
@@ -9,6 +9,7 @@ mod validation;
|
||||
#[cfg(target_os = "macos")]
|
||||
use crate::metrics::{KvLookup, Metrics};
|
||||
use crate::model::ModelChoice;
|
||||
#[cfg(target_os = "macos")]
|
||||
use crate::settings::TurnSettings;
|
||||
use crate::settings::{EngineSettings, ReasoningMode};
|
||||
use gguf::{F16, F32, Gguf, I32, IQ2_XXS, Q2_K, Q4_0, Q4_K, Q5_K, Q6_K, Q8_0, Tensor, Value};
|
||||
@@ -17,9 +18,12 @@ use kvstore::{KvStore, StoreReason};
|
||||
use sha2::{Digest, Sha256};
|
||||
#[cfg(target_os = "macos")]
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::Path;
|
||||
#[cfg(target_os = "macos")]
|
||||
use std::path::PathBuf;
|
||||
#[cfg(target_os = "macos")]
|
||||
use std::sync::Arc;
|
||||
#[cfg(target_os = "macos")]
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
#[cfg(target_os = "macos")]
|
||||
use std::time::Instant;
|
||||
@@ -1386,7 +1390,7 @@ impl Generator {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
fn append_generated_bytes(
|
||||
generated: &mut ChatTurn,
|
||||
reasoning: bool,
|
||||
@@ -1449,7 +1453,7 @@ fn flush_generated(
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
fn emit_safe_text(
|
||||
text: &mut String,
|
||||
emitted: &mut usize,
|
||||
@@ -1494,7 +1498,7 @@ fn emit_safe_text(
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
fn conversation_key(system: &str, reasoning: ReasoningMode, messages: &[ChatTurn]) -> Vec<u8> {
|
||||
fn text(output: &mut Vec<u8>, value: &str) {
|
||||
output.extend_from_slice(&(value.len() as u64).to_le_bytes());
|
||||
@@ -1526,12 +1530,12 @@ fn conversation_key(system: &str, reasoning: ReasoningMode, messages: &[ChatTurn
|
||||
output
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
fn conversation_tag(system: &str, reasoning: ReasoningMode, messages: &[ChatTurn]) -> [u8; 32] {
|
||||
Sha256::digest(conversation_key(system, reasoning, messages)).into()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
fn checkpoint_matches_prefix(
|
||||
checkpoint: [u8; 32],
|
||||
system: &str,
|
||||
@@ -1555,7 +1559,7 @@ fn resident_key(directory: &Path, tag: [u8; 32]) -> PathBuf {
|
||||
directory.join("resident").join(name)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
fn sample(
|
||||
logits: &[f32],
|
||||
temperature: f32,
|
||||
@@ -1631,10 +1635,10 @@ fn sample(
|
||||
probabilities.last().map_or(0, |(token, _)| *token as i32)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
struct Rng(u64);
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
impl Rng {
|
||||
fn new(seed: u64) -> Self {
|
||||
Self(seed.max(1))
|
||||
@@ -1654,7 +1658,7 @@ impl Rng {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, target_os = "macos"))]
|
||||
#[cfg(test)]
|
||||
mod sampling_tests {
|
||||
use super::*;
|
||||
|
||||
@@ -1835,6 +1839,7 @@ mod sampling_tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[ignore = "requires the 80 GiB Flash checkpoint and Apple Metal"]
|
||||
fn metal_executes_real_flash_token() {
|
||||
configure_metal_sources().unwrap();
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![cfg_attr(not(target_os = "macos"), allow(dead_code))]
|
||||
|
||||
mod a2ui;
|
||||
mod a2ui_validation;
|
||||
mod agent;
|
||||
@@ -6,6 +8,7 @@ mod compaction;
|
||||
mod config;
|
||||
mod database;
|
||||
mod dev_brain;
|
||||
mod dsml;
|
||||
mod engine;
|
||||
mod metrics;
|
||||
mod model;
|
||||
|
||||
@@ -312,49 +312,6 @@ impl Drop for ConnectionSlot {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_dsml_tool_calls(text: &str) -> Result<(String, Vec<(String, Value)>), String> {
|
||||
let has_tool_marker = TOOL_SYNTAXES
|
||||
.iter()
|
||||
.any(|syntax| text.contains(syntax.tool_start));
|
||||
let mut projector = ToolProjector::new();
|
||||
let events = projector.push(text, true, "");
|
||||
let mut content = String::new();
|
||||
let mut calls = Vec::<(String, String, bool)>::new();
|
||||
for event in events {
|
||||
match event {
|
||||
ToolProjectionEvent::Text(text) => content.push_str(&text),
|
||||
ToolProjectionEvent::Start { index, name, .. } => {
|
||||
if calls.len() == index {
|
||||
calls.push((name, String::new(), false));
|
||||
}
|
||||
}
|
||||
ToolProjectionEvent::Arguments { index, fragment } => {
|
||||
if let Some((_, arguments, _)) = calls.get_mut(index) {
|
||||
arguments.push_str(&fragment);
|
||||
}
|
||||
}
|
||||
ToolProjectionEvent::End { index } => {
|
||||
if let Some((_, _, complete)) = calls.get_mut(index) {
|
||||
*complete = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let calls = calls
|
||||
.into_iter()
|
||||
.filter(|(_, _, complete)| *complete)
|
||||
.map(|(name, arguments, _)| {
|
||||
serde_json::from_str(&arguments)
|
||||
.map(|arguments| (name, arguments))
|
||||
.map_err(|error| format!("invalid DSML tool arguments: {error}"))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
if has_tool_marker && calls.is_empty() {
|
||||
return Err("invalid or incomplete DSML tool call".into());
|
||||
}
|
||||
Ok((content, calls))
|
||||
}
|
||||
|
||||
fn handle(mut stream: TcpStream, state: &State) {
|
||||
let _ = stream.set_write_timeout(Some(HTTP_IO_TIMEOUT));
|
||||
let started = Instant::now();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::*;
|
||||
pub(super) use crate::dsml::{SYNTAXES as TOOL_SYNTAXES, Syntax as ToolSyntax};
|
||||
|
||||
const TOOL_MEMORY_FILE: &str = "tool-replay.json";
|
||||
const TOOL_MEMORY_MAX_IDS: usize = 100_000;
|
||||
@@ -698,43 +699,6 @@ fn repair_generated_tools(text: &str) -> Option<String> {
|
||||
Some(repaired)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(super) struct ToolSyntax {
|
||||
pub(super) tool_start: &'static str,
|
||||
pub(super) tool_end: &'static str,
|
||||
pub(super) invoke_start: &'static str,
|
||||
pub(super) invoke_end: &'static str,
|
||||
pub(super) parameter_start: &'static str,
|
||||
pub(super) parameter_end: &'static str,
|
||||
}
|
||||
|
||||
pub(super) const TOOL_SYNTAXES: [ToolSyntax; 3] = [
|
||||
ToolSyntax {
|
||||
tool_start: "<|DSML|tool_calls>",
|
||||
tool_end: "</|DSML|tool_calls>",
|
||||
invoke_start: "<|DSML|invoke",
|
||||
invoke_end: "</|DSML|invoke>",
|
||||
parameter_start: "<|DSML|parameter",
|
||||
parameter_end: "</|DSML|parameter>",
|
||||
},
|
||||
ToolSyntax {
|
||||
tool_start: "<DSML|tool_calls>",
|
||||
tool_end: "</DSML|tool_calls>",
|
||||
invoke_start: "<DSML|invoke",
|
||||
invoke_end: "</DSML|invoke>",
|
||||
parameter_start: "<DSML|parameter",
|
||||
parameter_end: "</DSML|parameter>",
|
||||
},
|
||||
ToolSyntax {
|
||||
tool_start: "<tool_calls>",
|
||||
tool_end: "</tool_calls>",
|
||||
invoke_start: "<invoke",
|
||||
invoke_end: "</invoke>",
|
||||
parameter_start: "<parameter",
|
||||
parameter_end: "</parameter>",
|
||||
},
|
||||
];
|
||||
|
||||
fn parse_tool_parameter(
|
||||
text: &str,
|
||||
cursor: &mut usize,
|
||||
|
||||
Reference in New Issue
Block a user