Lot 6 : parité d'un tour complet avec le Go (journal d'affichage)

internal/loki/parity_turn_test.go passe sept tours par la vraie route
/api/chat/send du Go contre un faux moteur — réponse simple, raisonnement,
outil puis réponse, « pensé sans agir », erreur du moteur, et en mode Code
un contrat déjà tenu et un contrat abandonné après deux corrections — et
range dans rust/loki-rs/tests/parity_turn/ le journal d'affichage du tour
(coalescé, mesures et horodatages masqués), l'historique rangé, les corps
envoyés au moteur, ainsi que les réponses du Go que la façade demandera
pendant ce tour (/turn/start, /turn/view, /turn/verifier). Ce que le prompt
de la machine porte de propre au lancement (dossiers temporaires,
discussion, date, hôte) est masqué des deux côtés.

tests/lot6.rs (parite_du_tour_complet) rejoue les sept tours par
chat::generate et retrouve journal, historique et requêtes à l'identique,
numérotation du journal coalescé comprise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
This commit is contained in:
Claude committed 2026-10-15 12:28:24 +00:00
1 parent f11f667a4c
commit dc262a44b8
10 files changed
+8298 -5

No files matched your search

+18 -5
View File
@@ -56,6 +56,12 @@ pub struct FakeGo {
pub tool_log: Mutex<Vec<String>>,
/// Le Go garde la conversation (raison), sinon la façade la tient.
pub go_keeps_chat: Mutex<Option<String>>,
/// Réponses imposées de /turn/start et /turn/view (journaux de référence
/// du Go), et résultat par outil.
pub turn_start: Mutex<Option<serde_json::Value>>,
pub turn_view: Mutex<Option<serde_json::Value>>,
pub turn_verifier: Mutex<Option<serde_json::Value>>,
pub tool_results: Mutex<HashMap<String, String>>,
}
impl FakeGo {
@@ -219,6 +225,9 @@ async fn handle(st: Arc<FakeGo>, req: Request<Incoming>) -> Response<Full<Bytes>
if msg.trim().is_empty() {
return resp(400, r#"{"error":"message vide"}"#);
}
if let Some(v) = st.turn_start.lock().unwrap().clone() {
return resp(200, v.to_string());
}
let code = *st.code.lock().unwrap();
let caps = serde_json::json!({"Agent": true, "Mem": "off", "Code": code, "Role": ""});
let out = serde_json::json!({
@@ -229,6 +238,9 @@ async fn handle(st: Arc<FakeGo>, req: Request<Incoming>) -> Response<Full<Bytes>
}
"/internal/v1/turn/view" => {
st.turn_log.lock().unwrap().push("view".into());
if let Some(v) = st.turn_view.lock().unwrap().clone() {
return resp(200, v.to_string());
}
let out = serde_json::json!({
"head": [{"role": "system", "content": "Tu es Loki."}],
"prefix": "PRÉAMBULE",
@@ -258,6 +270,9 @@ async fn handle(st: Arc<FakeGo>, req: Request<Incoming>) -> Response<Full<Bytes>
let body = req.into_body().collect().await.unwrap().to_bytes();
let v: serde_json::Value = serde_json::from_slice(&body).unwrap_or_default();
st.turn_log.lock().unwrap().push("verifier".into());
if let Some(out) = st.turn_verifier.lock().unwrap().clone() {
return resp(200, out.to_string());
}
let mut caps = v["caps"].clone();
caps["Role"] = "verifier".into();
let out = serde_json::json!({
@@ -317,11 +332,9 @@ async fn handle(st: Arc<FakeGo>, req: Request<Incoming>) -> Response<Full<Bytes>
*val = serde_json::to_vec(&list).unwrap();
}
}
let result = st
.tool_result
.lock()
.unwrap()
.clone()
let by_name = st.tool_results.lock().unwrap().get(name).cloned();
let result = by_name
.or_else(|| st.tool_result.lock().unwrap().clone())
.unwrap_or_else(|| format!("exec:{}", v["name"].as_str().unwrap()));
let out = serde_json::json!({
"label": v["args"]["command"],
+125
View File
@@ -554,6 +554,17 @@ async fn fake_engine_gated(
g.acquire().await.unwrap().forget();
}
let out = replies.lock().unwrap().pop_front().unwrap_or_default();
// « STATUS 400\n<corps> » : refus du moteur.
if let Some(rest) = out.strip_prefix("STATUS ")
&& let Some((code, body)) = rest.split_once('\n')
{
let mut r = hyper::Response::new(Full::new(bytes::Bytes::from(
body.to_string(),
)));
*r.status_mut() =
hyper::StatusCode::from_u16(code.parse().unwrap()).unwrap();
return Ok(r);
}
ok(out)
}
},
@@ -1443,3 +1454,117 @@ async fn deverrouillage_recharge_la_discussion_chargee_vide() {
// Déjà rempli : jamais rechargé par-dessus.
assert_eq!(s.reload_if_empty().await, Ok(false));
}
/// Parité d'un tour COMPLET avec le Go (`tests/parity_turn/*.json`, produits
/// par `TestPariteTourComplet` en passant par la vraie route /api/chat/send) :
/// le Go de test sert les mêmes réponses de /turn/start et /turn/view que le
/// vrai, le moteur les mêmes flux, les outils les mêmes résultats. Doivent se
/// retrouver : le journal d'affichage du tour (mesures masquées), l'historique
/// rangé, et les corps envoyés au moteur.
#[tokio::test]
async fn parite_du_tour_complet() {
let dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/parity_turn");
let mut paths: Vec<_> = std::fs::read_dir(&dir)
.unwrap()
.map(|e| e.unwrap().path())
.filter(|p| p.extension().is_some_and(|x| x == "json"))
.collect();
paths.sort();
assert!(!paths.is_empty());
let mut failures = Vec::new();
for p in &paths {
let fx: serde_json::Value = serde_json::from_slice(&std::fs::read(p).unwrap()).unwrap();
let name = fx["name"].as_str().unwrap().to_string();
let replies: Vec<String> = fx["replies"]
.as_array()
.unwrap()
.iter()
.map(|r| {
let body: String = r["lines"]
.as_array()
.unwrap()
.iter()
.map(|l| format!("{}\n\n", l.as_str().unwrap()))
.collect();
match r["status"].as_u64().unwrap() {
200 => body,
s => format!("STATUS {s}\n{body}"),
}
})
.collect();
let (url, seen) = fake_engine(replies).await;
let (svc, go, _stop, _t) = service(Some(&url)).await;
*go.turn_start.lock().unwrap() = Some(fx["start"].clone());
*go.turn_view.lock().unwrap() = Some(fx["view"].clone());
*go.tool_results.lock().unwrap() =
serde_json::from_value(fx["tool_results"].clone()).unwrap();
if !fx["verifier"].is_null() {
*go.turn_verifier.lock().unwrap() = Some(fx["verifier"].clone());
}
if let Some(c) = fx.get("criteria") {
let id = svc.sessions.conv().id();
go.set("chat", &format!("crit:{id}"), &c.to_string());
}
let sent = svc.send(fx["send"].clone()).await;
let status = if sent.is_ok() { 200 } else { 0 };
until_done(&svc, 1).await;
until(|| go.turn_log.lock().unwrap().contains(&"done".to_string())).await;
let exp = &fx["expect"];
let mut diffs = Vec::new();
if status != exp["status"].as_u64().unwrap() {
diffs.push(format!("statut {status}, attendu {}", exp["status"]));
}
let requests: Vec<serde_json::Value> = seen
.lock()
.unwrap()
.iter()
.map(|(_, b)| b.clone())
.collect();
if serde_json::Value::Array(requests.clone()) != exp["requests"] {
diffs.push(format!(
"requêtes :\n obtenu {}\n attendu {}",
serde_json::Value::Array(requests),
exp["requests"]
));
}
let log: Vec<serde_json::Value> = svc.sessions.conv().with_state(|st| {
st.log
.iter()
.map(|e| {
let mut d = e.delta.clone();
d.remove("ts0");
if d.contains_key("stats") {
d.insert("stats".into(), serde_json::json!("…"));
}
serde_json::Value::Object(d)
})
.collect()
});
if serde_json::Value::Array(log.clone()) != exp["log"] {
diffs.push(format!(
"journal :\n obtenu {}\n attendu {}",
serde_json::Value::Array(log),
exp["log"]
));
}
let msgs = svc.sessions.conv().with_state(|st| st.messages.clone());
let msgs = serde_json::to_value(&msgs).unwrap();
if msgs != exp["messages"] {
diffs.push(format!(
"historique :\n obtenu {msgs}\n attendu {}",
exp["messages"]
));
}
if !diffs.is_empty() {
failures.push(format!("{name} :\n{}", diffs.join("\n")));
}
}
assert!(
failures.is_empty(),
"{} tour(s) sur {} divergent du Go :\n\n{}",
failures.len(),
paths.len(),
failures.join("\n\n")
);
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,88 @@
{
"name": "erreur_moteur",
"cfg": {
"MEM_MODE": "off"
},
"send": {
"cid": "c-erreur_moteur",
"message": "Bonjour"
},
"replies": [
{
"status": 400,
"lines": [
"{\"error\":{\"code\":400,\"message\":\"requête invalide\",\"type\":\"invalid_request_error\"}}"
]
}
],
"tool_results": {
"bash": "a.txt\nb.txt",
"read": "1: ligne"
},
"start": {
"caps": {
"Agent": false,
"Code": false,
"ComputerUse": false,
"Internet": false,
"Mem": "off",
"Role": ""
},
"code_hint": false,
"content": "Bonjour",
"files": [],
"model": "",
"turn_caps": {
"Agent": false,
"Code": false,
"ComputerUse": false,
"Internet": false,
"Mem": "off",
"Role": ""
}
},
"view": {
"head": [],
"prefix": "",
"tools": []
},
"expect": {
"requests": [
{
"messages": [
{
"content": "Bonjour",
"role": "user"
}
],
"model": "loki",
"stream": true,
"stream_options": {
"include_usage": true
},
"temperature": 0.7
}
],
"log": [
{
"user": "Bonjour"
},
{
"error": "llama-server a renvoyé 400 : {\"error\":{\"code\":400,\"message\":\"requête invalide\",\"type\":\"invalid_request_error\"}}"
},
{
"ctx_used": 5
},
{
"turn_done": true
}
],
"messages": [
{
"role": "user",
"content": "Bonjour"
}
],
"status": 200
}
}
@@ -0,0 +1,870 @@
{
"name": "outil_puis_reponse",
"cfg": {
"MEM_MODE": "off"
},
"agent": true,
"send": {
"cid": "c-outil_puis_reponse",
"message": "Liste les fichiers"
},
"replies": [
{
"status": 200,
"lines": [
"data: {\"choices\":[{\"delta\":{\"tool_calls\":[{\"function\":{\"arguments\":\"{\\\"command\\\":\\\"ls\\\"}\",\"name\":\"bash\"},\"id\":\"c1\",\"index\":0,\"type\":\"function\"}]}}]}",
"data: {\"choices\":[{\"delta\":{},\"finish_reason\":\"tool_calls\"}],\"usage\":{\"completion_tokens\":5,\"prompt_tokens\":100}}",
"data: [DONE]"
]
},
{
"status": 200,
"lines": [
"data: {\"choices\":[{\"delta\":{\"content\":\"Deux fichiers.\"}}]}",
"data: {\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\"}],\"usage\":{\"completion_tokens\":5,\"prompt_tokens\":100}}",
"data: [DONE]"
]
}
],
"tool_results": {
"bash": "a.txt\nb.txt",
"read": "1: ligne"
},
"start": {
"caps": {
"Agent": true,
"Code": false,
"ComputerUse": false,
"Internet": false,
"Mem": "off",
"Role": ""
},
"code_hint": false,
"content": "Liste les fichiers",
"files": [],
"model": "",
"turn_caps": {
"Agent": true,
"Code": false,
"ComputerUse": false,
"Internet": false,
"Mem": "off",
"Role": ""
}
},
"view": {
"head": [],
"prefix": "You are Loki, an expert assistant operating directly on this machine with real tools.\n\nThe shell is bash: use its syntax.\nFor anything about the system or files, use bash instead of guessing. Act immediately — call the right tool, then answer. Never end your turn after only thinking. Be concise.\nTo give the user a file, link it in Markdown with its path relative to your working directory — [le rapport](rapport.pdf) — which downloads it. A raw server path is useless: they read you in a browser.\nYou can schedule work for yourself with task_create — only for what must recur or happen later, never a one-off you can do now. A script from your scripts folder runs as a task with no model at all.\n\nDate: {{DATE}}\n\nMachine: host={{HOST}}, cwd={{TMP}}/workspace/discussions/{{CONV}}. This is your working folder: relative paths in write/edit/bash resolve here, and it is the DEFAULT place for scratch work — notes, outputs, a clone, a test. But it is DISPOSABLE: deleting the discussion wipes it. Any script you want to KEEP (or schedule), write it into your scripts folder {{TMP}}/scripts instead — a separate folder a workspace wipe won't touch; you write and run scripts there normally. Do NOT install or write files into system directories such as /usr/local/bin, /usr, /bin or /etc: those need root and are not yours. Only use an absolute path outside this folder (except your scripts folder) when the user explicitly named that location.",
"tools": [
{
"function": {
"description": "Run a shell command (bash syntax) and return stdout, stderr and exit code: inspect the system, read files and logs, run scripts. To CREATE or REWRITE a file use write instead — never echo/cat/python -c. Avoid destructive commands unless asked.",
"name": "bash",
"parameters": {
"properties": {
"command": {
"description": "The command",
"type": "string"
},
"timeout": {
"description": "Timeout s (default 30, max 300)",
"type": "integer"
}
},
"required": [
"command"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Create or replace a file with the exact content given (parent dirs created, content verbatim, no escaping). ALWAYS use this for a script or any text file — NEVER build one through the shell with echo, cat, python -c or Set-Content: quoting breaks.",
"name": "write",
"parameters": {
"properties": {
"content": {
"description": "Full content",
"type": "string"
},
"file": {
"description": "Path",
"type": "string"
}
},
"required": [
"file",
"content"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Patch a file by exact replacement: old → new. old must appear EXACTLY once (add context to make it unique). Prefer this over rewriting a whole file.",
"name": "edit",
"parameters": {
"properties": {
"file": {
"description": "Path",
"type": "string"
},
"new": {
"description": "Replacement",
"type": "string"
},
"old": {
"description": "Exact text to replace (unique)",
"type": "string"
}
},
"required": [
"file",
"old",
"new"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Bring back verbatim an earlier block archived when this conversation was compacted, from the id shown as recall:rN in the summary.",
"name": "recall",
"parameters": {
"properties": {
"id": {
"description": "Block id, e.g. \"r7\".",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Find an archived block and its recall id by keywords, when it is not listed in the current summary. Then call recall(id).",
"name": "recall_search",
"parameters": {
"properties": {
"limit": {
"description": "Default 5, max 20",
"type": "integer"
},
"query": {
"description": "Keywords describing the block.",
"type": "string"
}
},
"required": [
"query"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "List your scheduled tasks with their state, next run, and last result. Pass an id to get that task's full last report.",
"name": "task_list",
"parameters": {
"properties": {
"id": {
"description": "Show only this task, with its full last report",
"type": "string"
}
},
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Schedule work to run later, once or repeating. Give 'prompt' for an AI task, OR 'script' (a saved script name) for a script task that runs with no model and no tokens.",
"name": "task_create",
"parameters": {
"properties": {
"at": {
"description": "One-time task at this local time: \"HH:MM\" (next occurrence) or \"YYYY-MM-DD HH:MM\"",
"type": "string"
},
"enabled": {
"description": "Start active (default true)",
"type": "boolean"
},
"in_minutes": {
"description": "One-time task, N minutes from now",
"type": "integer"
},
"name": {
"type": "string"
},
"prompt": {
"description": "AI task: self-contained instruction to run each time (omit if using script)",
"type": "string"
},
"schedule": {
"description": "Repeating: \"@every 2h\" (interval), \"@every 1d@09:00\" (daily time), or a 5-field cron \"min hour dom mon dow\". Omit for a one-time task (use in_minutes or at)",
"type": "string"
},
"script": {
"description": "Script task: name of a script file you put in the scripts folder, run each time with no AI involved",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Change one or more fields of a scheduled task by id.",
"name": "task_update",
"parameters": {
"properties": {
"enabled": {
"description": "false pauses, true resumes",
"type": "boolean"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"prompt": {
"type": "string"
},
"schedule": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Delete a scheduled task by id.",
"name": "task_delete",
"parameters": {
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
}
]
},
"expect": {
"requests": [
{
"messages": [
{
"content": "You are Loki, an expert assistant operating directly on this machine with real tools.\n\nThe shell is bash: use its syntax.\nFor anything about the system or files, use bash instead of guessing. Act immediately — call the right tool, then answer. Never end your turn after only thinking. Be concise.\nTo give the user a file, link it in Markdown with its path relative to your working directory — [le rapport](rapport.pdf) — which downloads it. A raw server path is useless: they read you in a browser.\nYou can schedule work for yourself with task_create — only for what must recur or happen later, never a one-off you can do now. A script from your scripts folder runs as a task with no model at all.\n\nDate: {{DATE}}\n\nMachine: host={{HOST}}, cwd={{TMP}}/workspace/discussions/{{CONV}}. This is your working folder: relative paths in write/edit/bash resolve here, and it is the DEFAULT place for scratch work — notes, outputs, a clone, a test. But it is DISPOSABLE: deleting the discussion wipes it. Any script you want to KEEP (or schedule), write it into your scripts folder {{TMP}}/scripts instead — a separate folder a workspace wipe won't touch; you write and run scripts there normally. Do NOT install or write files into system directories such as /usr/local/bin, /usr, /bin or /etc: those need root and are not yours. Only use an absolute path outside this folder (except your scripts folder) when the user explicitly named that location.",
"role": "system"
},
{
"content": "Liste les fichiers",
"role": "user"
}
],
"model": "loki",
"parallel_tool_calls": false,
"stream": true,
"stream_options": {
"include_usage": true
},
"temperature": 0.7,
"tools": [
{
"function": {
"description": "Run a shell command (bash syntax) and return stdout, stderr and exit code: inspect the system, read files and logs, run scripts. To CREATE or REWRITE a file use write instead — never echo/cat/python -c. Avoid destructive commands unless asked.",
"name": "bash",
"parameters": {
"properties": {
"command": {
"description": "The command",
"type": "string"
},
"timeout": {
"description": "Timeout s (default 30, max 300)",
"type": "integer"
}
},
"required": [
"command"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Create or replace a file with the exact content given (parent dirs created, content verbatim, no escaping). ALWAYS use this for a script or any text file — NEVER build one through the shell with echo, cat, python -c or Set-Content: quoting breaks.",
"name": "write",
"parameters": {
"properties": {
"content": {
"description": "Full content",
"type": "string"
},
"file": {
"description": "Path",
"type": "string"
}
},
"required": [
"file",
"content"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Patch a file by exact replacement: old → new. old must appear EXACTLY once (add context to make it unique). Prefer this over rewriting a whole file.",
"name": "edit",
"parameters": {
"properties": {
"file": {
"description": "Path",
"type": "string"
},
"new": {
"description": "Replacement",
"type": "string"
},
"old": {
"description": "Exact text to replace (unique)",
"type": "string"
}
},
"required": [
"file",
"old",
"new"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Bring back verbatim an earlier block archived when this conversation was compacted, from the id shown as recall:rN in the summary.",
"name": "recall",
"parameters": {
"properties": {
"id": {
"description": "Block id, e.g. \"r7\".",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Find an archived block and its recall id by keywords, when it is not listed in the current summary. Then call recall(id).",
"name": "recall_search",
"parameters": {
"properties": {
"limit": {
"description": "Default 5, max 20",
"type": "integer"
},
"query": {
"description": "Keywords describing the block.",
"type": "string"
}
},
"required": [
"query"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "List your scheduled tasks with their state, next run, and last result. Pass an id to get that task's full last report.",
"name": "task_list",
"parameters": {
"properties": {
"id": {
"description": "Show only this task, with its full last report",
"type": "string"
}
},
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Schedule work to run later, once or repeating. Give 'prompt' for an AI task, OR 'script' (a saved script name) for a script task that runs with no model and no tokens.",
"name": "task_create",
"parameters": {
"properties": {
"at": {
"description": "One-time task at this local time: \"HH:MM\" (next occurrence) or \"YYYY-MM-DD HH:MM\"",
"type": "string"
},
"enabled": {
"description": "Start active (default true)",
"type": "boolean"
},
"in_minutes": {
"description": "One-time task, N minutes from now",
"type": "integer"
},
"name": {
"type": "string"
},
"prompt": {
"description": "AI task: self-contained instruction to run each time (omit if using script)",
"type": "string"
},
"schedule": {
"description": "Repeating: \"@every 2h\" (interval), \"@every 1d@09:00\" (daily time), or a 5-field cron \"min hour dom mon dow\". Omit for a one-time task (use in_minutes or at)",
"type": "string"
},
"script": {
"description": "Script task: name of a script file you put in the scripts folder, run each time with no AI involved",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Change one or more fields of a scheduled task by id.",
"name": "task_update",
"parameters": {
"properties": {
"enabled": {
"description": "false pauses, true resumes",
"type": "boolean"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"prompt": {
"type": "string"
},
"schedule": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Delete a scheduled task by id.",
"name": "task_delete",
"parameters": {
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
}
]
},
{
"messages": [
{
"content": "You are Loki, an expert assistant operating directly on this machine with real tools.\n\nThe shell is bash: use its syntax.\nFor anything about the system or files, use bash instead of guessing. Act immediately — call the right tool, then answer. Never end your turn after only thinking. Be concise.\nTo give the user a file, link it in Markdown with its path relative to your working directory — [le rapport](rapport.pdf) — which downloads it. A raw server path is useless: they read you in a browser.\nYou can schedule work for yourself with task_create — only for what must recur or happen later, never a one-off you can do now. A script from your scripts folder runs as a task with no model at all.\n\nDate: {{DATE}}\n\nMachine: host={{HOST}}, cwd={{TMP}}/workspace/discussions/{{CONV}}. This is your working folder: relative paths in write/edit/bash resolve here, and it is the DEFAULT place for scratch work — notes, outputs, a clone, a test. But it is DISPOSABLE: deleting the discussion wipes it. Any script you want to KEEP (or schedule), write it into your scripts folder {{TMP}}/scripts instead — a separate folder a workspace wipe won't touch; you write and run scripts there normally. Do NOT install or write files into system directories such as /usr/local/bin, /usr, /bin or /etc: those need root and are not yours. Only use an absolute path outside this folder (except your scripts folder) when the user explicitly named that location.",
"role": "system"
},
{
"content": "Liste les fichiers",
"role": "user"
},
{
"role": "assistant",
"tool_calls": [
{
"function": {
"arguments": "{\"command\":\"ls\"}",
"name": "bash"
},
"id": "c1",
"type": "function"
}
]
},
{
"content": "a.txt\nb.txt",
"role": "tool",
"tool_call_id": "c1"
}
],
"model": "loki",
"parallel_tool_calls": false,
"stream": true,
"stream_options": {
"include_usage": true
},
"temperature": 0.7,
"tools": [
{
"function": {
"description": "Run a shell command (bash syntax) and return stdout, stderr and exit code: inspect the system, read files and logs, run scripts. To CREATE or REWRITE a file use write instead — never echo/cat/python -c. Avoid destructive commands unless asked.",
"name": "bash",
"parameters": {
"properties": {
"command": {
"description": "The command",
"type": "string"
},
"timeout": {
"description": "Timeout s (default 30, max 300)",
"type": "integer"
}
},
"required": [
"command"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Create or replace a file with the exact content given (parent dirs created, content verbatim, no escaping). ALWAYS use this for a script or any text file — NEVER build one through the shell with echo, cat, python -c or Set-Content: quoting breaks.",
"name": "write",
"parameters": {
"properties": {
"content": {
"description": "Full content",
"type": "string"
},
"file": {
"description": "Path",
"type": "string"
}
},
"required": [
"file",
"content"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Patch a file by exact replacement: old → new. old must appear EXACTLY once (add context to make it unique). Prefer this over rewriting a whole file.",
"name": "edit",
"parameters": {
"properties": {
"file": {
"description": "Path",
"type": "string"
},
"new": {
"description": "Replacement",
"type": "string"
},
"old": {
"description": "Exact text to replace (unique)",
"type": "string"
}
},
"required": [
"file",
"old",
"new"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Bring back verbatim an earlier block archived when this conversation was compacted, from the id shown as recall:rN in the summary.",
"name": "recall",
"parameters": {
"properties": {
"id": {
"description": "Block id, e.g. \"r7\".",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Find an archived block and its recall id by keywords, when it is not listed in the current summary. Then call recall(id).",
"name": "recall_search",
"parameters": {
"properties": {
"limit": {
"description": "Default 5, max 20",
"type": "integer"
},
"query": {
"description": "Keywords describing the block.",
"type": "string"
}
},
"required": [
"query"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "List your scheduled tasks with their state, next run, and last result. Pass an id to get that task's full last report.",
"name": "task_list",
"parameters": {
"properties": {
"id": {
"description": "Show only this task, with its full last report",
"type": "string"
}
},
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Schedule work to run later, once or repeating. Give 'prompt' for an AI task, OR 'script' (a saved script name) for a script task that runs with no model and no tokens.",
"name": "task_create",
"parameters": {
"properties": {
"at": {
"description": "One-time task at this local time: \"HH:MM\" (next occurrence) or \"YYYY-MM-DD HH:MM\"",
"type": "string"
},
"enabled": {
"description": "Start active (default true)",
"type": "boolean"
},
"in_minutes": {
"description": "One-time task, N minutes from now",
"type": "integer"
},
"name": {
"type": "string"
},
"prompt": {
"description": "AI task: self-contained instruction to run each time (omit if using script)",
"type": "string"
},
"schedule": {
"description": "Repeating: \"@every 2h\" (interval), \"@every 1d@09:00\" (daily time), or a 5-field cron \"min hour dom mon dow\". Omit for a one-time task (use in_minutes or at)",
"type": "string"
},
"script": {
"description": "Script task: name of a script file you put in the scripts folder, run each time with no AI involved",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Change one or more fields of a scheduled task by id.",
"name": "task_update",
"parameters": {
"properties": {
"enabled": {
"description": "false pauses, true resumes",
"type": "boolean"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"prompt": {
"type": "string"
},
"schedule": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Delete a scheduled task by id.",
"name": "task_delete",
"parameters": {
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
}
]
}
],
"log": [
{
"user": "Liste les fichiers"
},
{
"stats": "…"
},
{
"stats": "…"
},
{
"stats": "…"
},
{
"tool_used": {
"done": true,
"label": "ls",
"name": "bash",
"result": "a.txt\nb.txt",
"result_chars": 11,
"typing": false
}
},
{
"content": "Deux fichiers.",
"seq0": 8,
"toks": 1
},
{
"stats": "…"
},
{
"stats": "…"
},
{
"stats": "…"
},
{
"turn_done": true
}
],
"messages": [
{
"role": "user",
"content": "Liste les fichiers"
},
{
"role": "assistant",
"tool_calls": [
{
"id": "c1",
"type": "function",
"function": {
"name": "bash",
"arguments": "{\"command\":\"ls\"}"
}
}
]
},
{
"role": "tool",
"content": "a.txt\nb.txt",
"tool_call_id": "c1"
},
{
"role": "assistant",
"content": "Deux fichiers."
}
],
"status": 200
}
}
@@ -0,0 +1,836 @@
{
"name": "pense_sans_agir",
"cfg": {
"MEM_MODE": "off"
},
"agent": true,
"send": {
"cid": "c-pense_sans_agir",
"message": "Cherche"
},
"replies": [
{
"status": 200,
"lines": [
"data: {\"choices\":[{\"delta\":{\"reasoning_content\":\"Il faudrait lister.\"}}]}",
"data: {\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\"}],\"usage\":{\"completion_tokens\":5,\"prompt_tokens\":100}}",
"data: [DONE]"
]
},
{
"status": 200,
"lines": [
"data: {\"choices\":[{\"delta\":{\"content\":\"Voilà.\"}}]}",
"data: {\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\"}],\"usage\":{\"completion_tokens\":5,\"prompt_tokens\":100}}",
"data: [DONE]"
]
}
],
"tool_results": {
"bash": "a.txt\nb.txt",
"read": "1: ligne"
},
"start": {
"caps": {
"Agent": true,
"Code": false,
"ComputerUse": false,
"Internet": false,
"Mem": "off",
"Role": ""
},
"code_hint": false,
"content": "Cherche",
"files": [],
"model": "",
"turn_caps": {
"Agent": true,
"Code": false,
"ComputerUse": false,
"Internet": false,
"Mem": "off",
"Role": ""
}
},
"view": {
"head": [],
"prefix": "You are Loki, an expert assistant operating directly on this machine with real tools.\n\nThe shell is bash: use its syntax.\nFor anything about the system or files, use bash instead of guessing. Act immediately — call the right tool, then answer. Never end your turn after only thinking. Be concise.\nTo give the user a file, link it in Markdown with its path relative to your working directory — [le rapport](rapport.pdf) — which downloads it. A raw server path is useless: they read you in a browser.\nYou can schedule work for yourself with task_create — only for what must recur or happen later, never a one-off you can do now. A script from your scripts folder runs as a task with no model at all.\n\nDate: {{DATE}}\n\nMachine: host={{HOST}}, cwd={{TMP}}/workspace/discussions/{{CONV}}. This is your working folder: relative paths in write/edit/bash resolve here, and it is the DEFAULT place for scratch work — notes, outputs, a clone, a test. But it is DISPOSABLE: deleting the discussion wipes it. Any script you want to KEEP (or schedule), write it into your scripts folder {{TMP}}/scripts instead — a separate folder a workspace wipe won't touch; you write and run scripts there normally. Do NOT install or write files into system directories such as /usr/local/bin, /usr, /bin or /etc: those need root and are not yours. Only use an absolute path outside this folder (except your scripts folder) when the user explicitly named that location.",
"tools": [
{
"function": {
"description": "Run a shell command (bash syntax) and return stdout, stderr and exit code: inspect the system, read files and logs, run scripts. To CREATE or REWRITE a file use write instead — never echo/cat/python -c. Avoid destructive commands unless asked.",
"name": "bash",
"parameters": {
"properties": {
"command": {
"description": "The command",
"type": "string"
},
"timeout": {
"description": "Timeout s (default 30, max 300)",
"type": "integer"
}
},
"required": [
"command"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Create or replace a file with the exact content given (parent dirs created, content verbatim, no escaping). ALWAYS use this for a script or any text file — NEVER build one through the shell with echo, cat, python -c or Set-Content: quoting breaks.",
"name": "write",
"parameters": {
"properties": {
"content": {
"description": "Full content",
"type": "string"
},
"file": {
"description": "Path",
"type": "string"
}
},
"required": [
"file",
"content"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Patch a file by exact replacement: old → new. old must appear EXACTLY once (add context to make it unique). Prefer this over rewriting a whole file.",
"name": "edit",
"parameters": {
"properties": {
"file": {
"description": "Path",
"type": "string"
},
"new": {
"description": "Replacement",
"type": "string"
},
"old": {
"description": "Exact text to replace (unique)",
"type": "string"
}
},
"required": [
"file",
"old",
"new"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Bring back verbatim an earlier block archived when this conversation was compacted, from the id shown as recall:rN in the summary.",
"name": "recall",
"parameters": {
"properties": {
"id": {
"description": "Block id, e.g. \"r7\".",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Find an archived block and its recall id by keywords, when it is not listed in the current summary. Then call recall(id).",
"name": "recall_search",
"parameters": {
"properties": {
"limit": {
"description": "Default 5, max 20",
"type": "integer"
},
"query": {
"description": "Keywords describing the block.",
"type": "string"
}
},
"required": [
"query"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "List your scheduled tasks with their state, next run, and last result. Pass an id to get that task's full last report.",
"name": "task_list",
"parameters": {
"properties": {
"id": {
"description": "Show only this task, with its full last report",
"type": "string"
}
},
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Schedule work to run later, once or repeating. Give 'prompt' for an AI task, OR 'script' (a saved script name) for a script task that runs with no model and no tokens.",
"name": "task_create",
"parameters": {
"properties": {
"at": {
"description": "One-time task at this local time: \"HH:MM\" (next occurrence) or \"YYYY-MM-DD HH:MM\"",
"type": "string"
},
"enabled": {
"description": "Start active (default true)",
"type": "boolean"
},
"in_minutes": {
"description": "One-time task, N minutes from now",
"type": "integer"
},
"name": {
"type": "string"
},
"prompt": {
"description": "AI task: self-contained instruction to run each time (omit if using script)",
"type": "string"
},
"schedule": {
"description": "Repeating: \"@every 2h\" (interval), \"@every 1d@09:00\" (daily time), or a 5-field cron \"min hour dom mon dow\". Omit for a one-time task (use in_minutes or at)",
"type": "string"
},
"script": {
"description": "Script task: name of a script file you put in the scripts folder, run each time with no AI involved",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Change one or more fields of a scheduled task by id.",
"name": "task_update",
"parameters": {
"properties": {
"enabled": {
"description": "false pauses, true resumes",
"type": "boolean"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"prompt": {
"type": "string"
},
"schedule": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Delete a scheduled task by id.",
"name": "task_delete",
"parameters": {
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
}
]
},
"expect": {
"requests": [
{
"messages": [
{
"content": "You are Loki, an expert assistant operating directly on this machine with real tools.\n\nThe shell is bash: use its syntax.\nFor anything about the system or files, use bash instead of guessing. Act immediately — call the right tool, then answer. Never end your turn after only thinking. Be concise.\nTo give the user a file, link it in Markdown with its path relative to your working directory — [le rapport](rapport.pdf) — which downloads it. A raw server path is useless: they read you in a browser.\nYou can schedule work for yourself with task_create — only for what must recur or happen later, never a one-off you can do now. A script from your scripts folder runs as a task with no model at all.\n\nDate: {{DATE}}\n\nMachine: host={{HOST}}, cwd={{TMP}}/workspace/discussions/{{CONV}}. This is your working folder: relative paths in write/edit/bash resolve here, and it is the DEFAULT place for scratch work — notes, outputs, a clone, a test. But it is DISPOSABLE: deleting the discussion wipes it. Any script you want to KEEP (or schedule), write it into your scripts folder {{TMP}}/scripts instead — a separate folder a workspace wipe won't touch; you write and run scripts there normally. Do NOT install or write files into system directories such as /usr/local/bin, /usr, /bin or /etc: those need root and are not yours. Only use an absolute path outside this folder (except your scripts folder) when the user explicitly named that location.",
"role": "system"
},
{
"content": "Cherche",
"role": "user"
}
],
"model": "loki",
"parallel_tool_calls": false,
"stream": true,
"stream_options": {
"include_usage": true
},
"temperature": 0.7,
"tools": [
{
"function": {
"description": "Run a shell command (bash syntax) and return stdout, stderr and exit code: inspect the system, read files and logs, run scripts. To CREATE or REWRITE a file use write instead — never echo/cat/python -c. Avoid destructive commands unless asked.",
"name": "bash",
"parameters": {
"properties": {
"command": {
"description": "The command",
"type": "string"
},
"timeout": {
"description": "Timeout s (default 30, max 300)",
"type": "integer"
}
},
"required": [
"command"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Create or replace a file with the exact content given (parent dirs created, content verbatim, no escaping). ALWAYS use this for a script or any text file — NEVER build one through the shell with echo, cat, python -c or Set-Content: quoting breaks.",
"name": "write",
"parameters": {
"properties": {
"content": {
"description": "Full content",
"type": "string"
},
"file": {
"description": "Path",
"type": "string"
}
},
"required": [
"file",
"content"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Patch a file by exact replacement: old → new. old must appear EXACTLY once (add context to make it unique). Prefer this over rewriting a whole file.",
"name": "edit",
"parameters": {
"properties": {
"file": {
"description": "Path",
"type": "string"
},
"new": {
"description": "Replacement",
"type": "string"
},
"old": {
"description": "Exact text to replace (unique)",
"type": "string"
}
},
"required": [
"file",
"old",
"new"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Bring back verbatim an earlier block archived when this conversation was compacted, from the id shown as recall:rN in the summary.",
"name": "recall",
"parameters": {
"properties": {
"id": {
"description": "Block id, e.g. \"r7\".",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Find an archived block and its recall id by keywords, when it is not listed in the current summary. Then call recall(id).",
"name": "recall_search",
"parameters": {
"properties": {
"limit": {
"description": "Default 5, max 20",
"type": "integer"
},
"query": {
"description": "Keywords describing the block.",
"type": "string"
}
},
"required": [
"query"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "List your scheduled tasks with their state, next run, and last result. Pass an id to get that task's full last report.",
"name": "task_list",
"parameters": {
"properties": {
"id": {
"description": "Show only this task, with its full last report",
"type": "string"
}
},
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Schedule work to run later, once or repeating. Give 'prompt' for an AI task, OR 'script' (a saved script name) for a script task that runs with no model and no tokens.",
"name": "task_create",
"parameters": {
"properties": {
"at": {
"description": "One-time task at this local time: \"HH:MM\" (next occurrence) or \"YYYY-MM-DD HH:MM\"",
"type": "string"
},
"enabled": {
"description": "Start active (default true)",
"type": "boolean"
},
"in_minutes": {
"description": "One-time task, N minutes from now",
"type": "integer"
},
"name": {
"type": "string"
},
"prompt": {
"description": "AI task: self-contained instruction to run each time (omit if using script)",
"type": "string"
},
"schedule": {
"description": "Repeating: \"@every 2h\" (interval), \"@every 1d@09:00\" (daily time), or a 5-field cron \"min hour dom mon dow\". Omit for a one-time task (use in_minutes or at)",
"type": "string"
},
"script": {
"description": "Script task: name of a script file you put in the scripts folder, run each time with no AI involved",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Change one or more fields of a scheduled task by id.",
"name": "task_update",
"parameters": {
"properties": {
"enabled": {
"description": "false pauses, true resumes",
"type": "boolean"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"prompt": {
"type": "string"
},
"schedule": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Delete a scheduled task by id.",
"name": "task_delete",
"parameters": {
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
}
]
},
{
"messages": [
{
"content": "You are Loki, an expert assistant operating directly on this machine with real tools.\n\nThe shell is bash: use its syntax.\nFor anything about the system or files, use bash instead of guessing. Act immediately — call the right tool, then answer. Never end your turn after only thinking. Be concise.\nTo give the user a file, link it in Markdown with its path relative to your working directory — [le rapport](rapport.pdf) — which downloads it. A raw server path is useless: they read you in a browser.\nYou can schedule work for yourself with task_create — only for what must recur or happen later, never a one-off you can do now. A script from your scripts folder runs as a task with no model at all.\n\nDate: {{DATE}}\n\nMachine: host={{HOST}}, cwd={{TMP}}/workspace/discussions/{{CONV}}. This is your working folder: relative paths in write/edit/bash resolve here, and it is the DEFAULT place for scratch work — notes, outputs, a clone, a test. But it is DISPOSABLE: deleting the discussion wipes it. Any script you want to KEEP (or schedule), write it into your scripts folder {{TMP}}/scripts instead — a separate folder a workspace wipe won't touch; you write and run scripts there normally. Do NOT install or write files into system directories such as /usr/local/bin, /usr, /bin or /etc: those need root and are not yours. Only use an absolute path outside this folder (except your scripts folder) when the user explicitly named that location.",
"role": "system"
},
{
"content": "Cherche",
"role": "user"
},
{
"content": "You reasoned but did not call a tool or answer. Act NOW: call the appropriate tool directly (e.g. mem_search/mem_read/bash), or give your final answer if you already have the info. Don't explain, act.",
"role": "user"
}
],
"model": "loki",
"parallel_tool_calls": false,
"stream": true,
"stream_options": {
"include_usage": true
},
"temperature": 0.7,
"tools": [
{
"function": {
"description": "Run a shell command (bash syntax) and return stdout, stderr and exit code: inspect the system, read files and logs, run scripts. To CREATE or REWRITE a file use write instead — never echo/cat/python -c. Avoid destructive commands unless asked.",
"name": "bash",
"parameters": {
"properties": {
"command": {
"description": "The command",
"type": "string"
},
"timeout": {
"description": "Timeout s (default 30, max 300)",
"type": "integer"
}
},
"required": [
"command"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Create or replace a file with the exact content given (parent dirs created, content verbatim, no escaping). ALWAYS use this for a script or any text file — NEVER build one through the shell with echo, cat, python -c or Set-Content: quoting breaks.",
"name": "write",
"parameters": {
"properties": {
"content": {
"description": "Full content",
"type": "string"
},
"file": {
"description": "Path",
"type": "string"
}
},
"required": [
"file",
"content"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Patch a file by exact replacement: old → new. old must appear EXACTLY once (add context to make it unique). Prefer this over rewriting a whole file.",
"name": "edit",
"parameters": {
"properties": {
"file": {
"description": "Path",
"type": "string"
},
"new": {
"description": "Replacement",
"type": "string"
},
"old": {
"description": "Exact text to replace (unique)",
"type": "string"
}
},
"required": [
"file",
"old",
"new"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Bring back verbatim an earlier block archived when this conversation was compacted, from the id shown as recall:rN in the summary.",
"name": "recall",
"parameters": {
"properties": {
"id": {
"description": "Block id, e.g. \"r7\".",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Find an archived block and its recall id by keywords, when it is not listed in the current summary. Then call recall(id).",
"name": "recall_search",
"parameters": {
"properties": {
"limit": {
"description": "Default 5, max 20",
"type": "integer"
},
"query": {
"description": "Keywords describing the block.",
"type": "string"
}
},
"required": [
"query"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "List your scheduled tasks with their state, next run, and last result. Pass an id to get that task's full last report.",
"name": "task_list",
"parameters": {
"properties": {
"id": {
"description": "Show only this task, with its full last report",
"type": "string"
}
},
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Schedule work to run later, once or repeating. Give 'prompt' for an AI task, OR 'script' (a saved script name) for a script task that runs with no model and no tokens.",
"name": "task_create",
"parameters": {
"properties": {
"at": {
"description": "One-time task at this local time: \"HH:MM\" (next occurrence) or \"YYYY-MM-DD HH:MM\"",
"type": "string"
},
"enabled": {
"description": "Start active (default true)",
"type": "boolean"
},
"in_minutes": {
"description": "One-time task, N minutes from now",
"type": "integer"
},
"name": {
"type": "string"
},
"prompt": {
"description": "AI task: self-contained instruction to run each time (omit if using script)",
"type": "string"
},
"schedule": {
"description": "Repeating: \"@every 2h\" (interval), \"@every 1d@09:00\" (daily time), or a 5-field cron \"min hour dom mon dow\". Omit for a one-time task (use in_minutes or at)",
"type": "string"
},
"script": {
"description": "Script task: name of a script file you put in the scripts folder, run each time with no AI involved",
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Change one or more fields of a scheduled task by id.",
"name": "task_update",
"parameters": {
"properties": {
"enabled": {
"description": "false pauses, true resumes",
"type": "boolean"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"prompt": {
"type": "string"
},
"schedule": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
},
{
"function": {
"description": "Delete a scheduled task by id.",
"name": "task_delete",
"parameters": {
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
"type": "function"
}
]
}
],
"log": [
{
"user": "Cherche"
},
{
"reasoning_content": "Il faudrait lister.",
"seq0": 2,
"toks": 1
},
{
"stats": "…"
},
{
"stats": "…"
},
{
"stats": "…"
},
{
"drop_reasoning": true
},
{
"content": "Voilà.",
"seq0": 7,
"toks": 1
},
{
"stats": "…"
},
{
"stats": "…"
},
{
"stats": "…"
},
{
"turn_done": true
}
],
"messages": [
{
"role": "user",
"content": "Cherche"
},
{
"role": "assistant",
"content": "Voilà."
}
],
"status": 200
}
}
@@ -0,0 +1,108 @@
{
"name": "raisonnement",
"cfg": {
"MEM_MODE": "off"
},
"send": {
"cid": "c-raisonnement",
"message": "Combien ?"
},
"replies": [
{
"status": 200,
"lines": [
"data: {\"choices\":[{\"delta\":{\"reasoning_content\":\"Je compte.\"}}]}",
"data: {\"choices\":[{\"delta\":{\"content\":\"Quatre.\"}}]}",
"data: {\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\"}],\"usage\":{\"completion_tokens\":5,\"prompt_tokens\":100}}",
"data: [DONE]"
]
}
],
"tool_results": {
"bash": "a.txt\nb.txt",
"read": "1: ligne"
},
"start": {
"caps": {
"Agent": false,
"Code": false,
"ComputerUse": false,
"Internet": false,
"Mem": "off",
"Role": ""
},
"code_hint": false,
"content": "Combien ?",
"files": [],
"model": "",
"turn_caps": {
"Agent": false,
"Code": false,
"ComputerUse": false,
"Internet": false,
"Mem": "off",
"Role": ""
}
},
"view": {
"head": [],
"prefix": "",
"tools": []
},
"expect": {
"requests": [
{
"messages": [
{
"content": "Combien ?",
"role": "user"
}
],
"model": "loki",
"stream": true,
"stream_options": {
"include_usage": true
},
"temperature": 0.7
}
],
"log": [
{
"user": "Combien ?"
},
{
"reasoning_content": "Je compte.",
"seq0": 2,
"toks": 1
},
{
"content": "Quatre.",
"seq0": 3,
"toks": 1
},
{
"stats": "…"
},
{
"stats": "…"
},
{
"stats": "…"
},
{
"turn_done": true
}
],
"messages": [
{
"role": "user",
"content": "Combien ?"
},
{
"role": "assistant",
"content": "Quatre."
}
],
"status": 200
}
}
@@ -0,0 +1,103 @@
{
"name": "reponse_simple",
"cfg": {
"MEM_MODE": "off"
},
"send": {
"cid": "c-reponse_simple",
"message": "Bonjour"
},
"replies": [
{
"status": 200,
"lines": [
"data: {\"choices\":[{\"delta\":{\"content\":\"Bon\"}}]}",
"data: {\"choices\":[{\"delta\":{\"content\":\"jour !\"}}]}",
"data: {\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\"}],\"usage\":{\"completion_tokens\":5,\"prompt_tokens\":100}}",
"data: [DONE]"
]
}
],
"tool_results": {
"bash": "a.txt\nb.txt",
"read": "1: ligne"
},
"start": {
"caps": {
"Agent": false,
"Code": false,
"ComputerUse": false,
"Internet": false,
"Mem": "off",
"Role": ""
},
"code_hint": false,
"content": "Bonjour",
"files": [],
"model": "",
"turn_caps": {
"Agent": false,
"Code": false,
"ComputerUse": false,
"Internet": false,
"Mem": "off",
"Role": ""
}
},
"view": {
"head": [],
"prefix": "",
"tools": []
},
"expect": {
"requests": [
{
"messages": [
{
"content": "Bonjour",
"role": "user"
}
],
"model": "loki",
"stream": true,
"stream_options": {
"include_usage": true
},
"temperature": 0.7
}
],
"log": [
{
"user": "Bonjour"
},
{
"content": "Bonjour !",
"seq0": 2,
"toks": 2
},
{
"stats": "…"
},
{
"stats": "…"
},
{
"stats": "…"
},
{
"turn_done": true
}
],
"messages": [
{
"role": "user",
"content": "Bonjour"
},
{
"role": "assistant",
"content": "Bonjour !"
}
],
"status": 200
}
}