motifcode 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-info.json +3 -3
- package/dist/motif.js +91 -24
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
package/dist/motif.js
CHANGED
|
@@ -831,6 +831,32 @@ function looksLikeLeakedToolCall(result) {
|
|
|
831
831
|
if (result.unrecoverable.length > 0) return true;
|
|
832
832
|
return /<tool_call>|<\/tool_call>/.test(result.content);
|
|
833
833
|
}
|
|
834
|
+
function stripLoneFence(s) {
|
|
835
|
+
const m = /^```(?:json|tool_call)?\s*([\s\S]*?)\s*```$/.exec(s.trim());
|
|
836
|
+
return m ? (m[1] ?? "").trim() : s.trim();
|
|
837
|
+
}
|
|
838
|
+
function recoverBareToolCall(content, ctx) {
|
|
839
|
+
const body = stripLoneFence(content);
|
|
840
|
+
if (!body.startsWith("{") || !body.endsWith("}")) return null;
|
|
841
|
+
const strict = strictLoad(body);
|
|
842
|
+
const outcome = strict !== null ? { value: coerceArgumentsWrapper(strict), info: CLEAN } : repairBlockDetailed(body, ctx);
|
|
843
|
+
if (outcome.value === null) return null;
|
|
844
|
+
const name = typeof outcome.value["name"] === "string" ? outcome.value["name"] : "";
|
|
845
|
+
if (name === "" || !ctx.specs.has(name)) return null;
|
|
846
|
+
return {
|
|
847
|
+
name,
|
|
848
|
+
arguments: asArguments(outcome.value["arguments"]),
|
|
849
|
+
repaired: true,
|
|
850
|
+
repair: { kind: "detag", lossy: outcome.info.lossy, complete: outcome.info.complete }
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
function contentLeaksToolCall(content, ctx) {
|
|
854
|
+
if (/<\/?tool_call>/.test(content)) return true;
|
|
855
|
+
for (const m of content.matchAll(/\{[^{}]*"name"\s*:\s*"([a-z_]+)"[\s\S]*?\}/g)) {
|
|
856
|
+
if (ctx.specs.has(m[1])) return true;
|
|
857
|
+
}
|
|
858
|
+
return false;
|
|
859
|
+
}
|
|
834
860
|
|
|
835
861
|
// packages/protocol/src/scrubber.ts
|
|
836
862
|
var MARKERS = [THINK_OPEN, THINK_CLOSE];
|
|
@@ -969,6 +995,24 @@ var ToolCallChannel = class {
|
|
|
969
995
|
...c.repair ? { repair: c.repair } : {}
|
|
970
996
|
}
|
|
971
997
|
);
|
|
998
|
+
if (actions.length === 0) {
|
|
999
|
+
const bare = recoverBareToolCall(r.content, ctx);
|
|
1000
|
+
if (bare) {
|
|
1001
|
+
const action = bare.name === "done" ? {
|
|
1002
|
+
kind: "done",
|
|
1003
|
+
summary: String(bare.arguments["summary"] ?? ""),
|
|
1004
|
+
...typeof bare.arguments["confirm"] === "boolean" ? { confirm: bare.arguments["confirm"] } : {},
|
|
1005
|
+
...bare.repair ? { repair: bare.repair } : {}
|
|
1006
|
+
} : {
|
|
1007
|
+
kind: "tool",
|
|
1008
|
+
name: bare.name,
|
|
1009
|
+
arguments: bare.arguments,
|
|
1010
|
+
repaired: true,
|
|
1011
|
+
...bare.repair ? { repair: bare.repair } : {}
|
|
1012
|
+
};
|
|
1013
|
+
return { actions: [action], content: "", unrecoverable: [], truncated: false };
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
972
1016
|
return {
|
|
973
1017
|
actions,
|
|
974
1018
|
content: r.content.trim(),
|
|
@@ -2931,7 +2975,7 @@ async function runLoop(opts) {
|
|
|
2931
2975
|
} : { id: nextId(), name: a.name, arguments: a.arguments }
|
|
2932
2976
|
);
|
|
2933
2977
|
if (parsed.actions.length === 0) {
|
|
2934
|
-
const leaked = parsed.unrecoverable.length > 0 || parsed.truncated || (parsed.invalidArguments?.length ?? 0) > 0 || channel === "toolcall" && looksLikeLeakedToolCall(parseToolCalls(split.content, ctx));
|
|
2978
|
+
const leaked = parsed.unrecoverable.length > 0 || parsed.truncated || (parsed.invalidArguments?.length ?? 0) > 0 || channel === "toolcall" && (looksLikeLeakedToolCall(parseToolCalls(split.content, ctx)) || contentLeaksToolCall(split.content, ctx));
|
|
2935
2979
|
if (replyEnds && !leaked && response.finishReason !== "length") {
|
|
2936
2980
|
session.appendAll(codec.serializeAssistant(split.content, split.reasoning, parsed));
|
|
2937
2981
|
checkpoint();
|
|
@@ -2960,7 +3004,8 @@ async function runLoop(opts) {
|
|
|
2960
3004
|
leaked ? "Your last turn did not produce a usable action. It looks like action syntax that failed to parse." : "Your last turn produced no action.",
|
|
2961
3005
|
channel,
|
|
2962
3006
|
consecutiveNoAction,
|
|
2963
|
-
lastObservation
|
|
3007
|
+
lastObservation,
|
|
3008
|
+
!leaked
|
|
2964
3009
|
);
|
|
2965
3010
|
if (consecutiveNoAction === 1) {
|
|
2966
3011
|
handBack(nudge);
|
|
@@ -3160,8 +3205,8 @@ function refusalPrompt(refusals, channel) {
|
|
|
3160
3205
|
repairPrompt("", channel).trim()
|
|
3161
3206
|
].join("\n");
|
|
3162
3207
|
}
|
|
3163
|
-
function repairPrompt(problem, channel, attempt = 1, lastObservation = "") {
|
|
3164
|
-
const how = channel === "toolcall" ? "Emit a well-formed `<tool_call>` block. Watch backslashes: inside JSON strings, shell `$` and regex metacharacters must be escaped or avoided." : channel === "object" ? "Reply with a single well-formed JSON object matching the schema you were given." : "Reply with the XML shape you were given. Command bodies are verbatim \u2014 do not escape anything inside them.";
|
|
3208
|
+
function repairPrompt(problem, channel, attempt = 1, lastObservation = "", cleanReply = false) {
|
|
3209
|
+
const how = cleanReply ? "If the task is already complete, or the message only needs an answer, call `done` now with that answer as the summary. Otherwise take the next concrete step toward the task above \u2014 do not read files or run commands looking for unrelated work to do." : channel === "toolcall" ? "Emit a well-formed `<tool_call>` block. Watch backslashes: inside JSON strings, shell `$` and regex metacharacters must be escaped or avoided." : channel === "object" ? "Reply with a single well-formed JSON object matching the schema you were given." : "Reply with the XML shape you were given. Command bodies are verbatim \u2014 do not escape anything inside them.";
|
|
3165
3210
|
const parts = [problem, "", how];
|
|
3166
3211
|
if (attempt >= 2) {
|
|
3167
3212
|
parts.push(
|
|
@@ -6985,22 +7030,23 @@ async function doctor(opts) {
|
|
|
6985
7030
|
}
|
|
6986
7031
|
);
|
|
6987
7032
|
}
|
|
7033
|
+
const probeBody = JSON.stringify({
|
|
7034
|
+
model: opts.model,
|
|
7035
|
+
temperature: SAMPLING_DEFAULTS.temperature,
|
|
7036
|
+
top_p: SAMPLING_DEFAULTS.top_p,
|
|
7037
|
+
stream: false,
|
|
7038
|
+
max_tokens: 256,
|
|
7039
|
+
messages: [
|
|
7040
|
+
{ role: "system", content: "You are a coding agent. Finish by calling the `done` tool." },
|
|
7041
|
+
{ role: "user", content: 'Call `done` now with the summary "ok". Do nothing else.' }
|
|
7042
|
+
],
|
|
7043
|
+
tools: [PROBE_TOOL]
|
|
7044
|
+
});
|
|
6988
7045
|
try {
|
|
6989
7046
|
const res = await fetchImpl(`${endpoint}/v1/chat/completions`, {
|
|
6990
7047
|
method: "POST",
|
|
6991
7048
|
headers,
|
|
6992
|
-
body:
|
|
6993
|
-
model: opts.model,
|
|
6994
|
-
temperature: SAMPLING_DEFAULTS.temperature,
|
|
6995
|
-
top_p: SAMPLING_DEFAULTS.top_p,
|
|
6996
|
-
stream: false,
|
|
6997
|
-
max_tokens: 256,
|
|
6998
|
-
messages: [
|
|
6999
|
-
{ role: "system", content: "You are a coding agent. Finish by calling the `done` tool." },
|
|
7000
|
-
{ role: "user", content: 'Call `done` now with the summary "ok". Do nothing else.' }
|
|
7001
|
-
],
|
|
7002
|
-
tools: [PROBE_TOOL]
|
|
7003
|
-
})
|
|
7049
|
+
body: probeBody
|
|
7004
7050
|
});
|
|
7005
7051
|
if (res.status === 401 || res.status === 403) {
|
|
7006
7052
|
const text = (await res.text().catch(() => "")).trim().slice(0, 200);
|
|
@@ -7047,12 +7093,31 @@ async function doctor(opts) {
|
|
|
7047
7093
|
fix: "the harness splits it client-side; that is a fallback, not the design"
|
|
7048
7094
|
} : { name: "reasoning parser", state: "unknown", detail: "no reasoning in the probe response" }
|
|
7049
7095
|
);
|
|
7050
|
-
|
|
7096
|
+
let cached2 = json.usage?.prompt_tokens_details?.cached_tokens;
|
|
7097
|
+
try {
|
|
7098
|
+
const again = await fetchImpl(`${endpoint}/v1/chat/completions`, {
|
|
7099
|
+
method: "POST",
|
|
7100
|
+
headers,
|
|
7101
|
+
body: probeBody
|
|
7102
|
+
});
|
|
7103
|
+
if (again.ok) {
|
|
7104
|
+
const json2 = await again.json();
|
|
7105
|
+
const c2 = json2.usage?.prompt_tokens_details?.cached_tokens;
|
|
7106
|
+
if (typeof c2 === "number") cached2 = c2;
|
|
7107
|
+
}
|
|
7108
|
+
} catch {
|
|
7109
|
+
}
|
|
7110
|
+
const reports = cached2 !== void 0;
|
|
7051
7111
|
checks.push(
|
|
7052
|
-
typeof cached2 === "number" ? {
|
|
7112
|
+
typeof cached2 === "number" && cached2 > 0 ? {
|
|
7053
7113
|
name: "prefix caching",
|
|
7054
7114
|
state: "ok",
|
|
7055
|
-
detail: `the endpoint
|
|
7115
|
+
detail: `the endpoint served ${cached2} prompt tokens from its prefix cache on a repeated request`
|
|
7116
|
+
} : reports ? {
|
|
7117
|
+
name: "prefix caching",
|
|
7118
|
+
state: "unknown",
|
|
7119
|
+
detail: "the endpoint reports cached tokens but served none on this probe",
|
|
7120
|
+
fix: "a two-request probe cannot always warm the cache; in a real session the frozen tool order keeps the prefix alive across turns"
|
|
7056
7121
|
} : {
|
|
7057
7122
|
name: "prefix caching",
|
|
7058
7123
|
state: "unknown",
|
|
@@ -9025,10 +9090,12 @@ function loadPlugins(opts) {
|
|
|
9025
9090
|
};
|
|
9026
9091
|
}
|
|
9027
9092
|
function describePlugins(loaded) {
|
|
9028
|
-
if (loaded.plugins.length === 0
|
|
9029
|
-
|
|
9030
|
-
|
|
9031
|
-
)
|
|
9093
|
+
if (loaded.plugins.length === 0 && loaded.problems.length === 0) {
|
|
9094
|
+
return ["no plugins; add one under ~/.motif/plugins/{name}/ or .motif/plugins/{name}/ with a plugin.json"];
|
|
9095
|
+
}
|
|
9096
|
+
const lines = loaded.plugins.map(function(p) {
|
|
9097
|
+
return `${p.name.padEnd(16)} ${p.description}${p.version ? ` (${p.version})` : ""} \xB7 ${p.source} \xB7 ${p.skills.length} skill(s)${p.skills.length ? `: ${p.skills.join(", ")}` : ""}${p.agents.length ? ` \xB7 ${p.agents.length} agent(s): ${p.agents.join(", ")}` : ""}`;
|
|
9098
|
+
});
|
|
9032
9099
|
for (const p of loaded.problems) lines.push(`! ${p}`);
|
|
9033
9100
|
return lines;
|
|
9034
9101
|
}
|
|
@@ -9144,7 +9211,7 @@ function saveUserSetting(key, value, home = homedir4()) {
|
|
|
9144
9211
|
}
|
|
9145
9212
|
|
|
9146
9213
|
// packages/cli/src/main.ts
|
|
9147
|
-
var VERSION = "0.
|
|
9214
|
+
var VERSION = "0.3.1";
|
|
9148
9215
|
var SHORT_FLAGS = { p: "print", c: "continue", i: "interactive", v: "verbose", h: "help" };
|
|
9149
9216
|
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
9150
9217
|
"print",
|