la-machina-engine 0.17.0 → 0.19.0
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/index.cjs +278 -354
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +201 -55
- package/dist/index.d.ts +201 -55
- package/dist/index.js +278 -354
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3986,6 +3986,29 @@ var RunContext = class {
|
|
|
3986
3986
|
});
|
|
3987
3987
|
this.episodes?.logTurn(this.turnCount, "user", text2);
|
|
3988
3988
|
}
|
|
3989
|
+
/**
|
|
3990
|
+
* Plan 051 — seed a prior chat turn into the run's message stack
|
|
3991
|
+
* before the current task. Writes a normal `user` / `assistant`
|
|
3992
|
+
* transcript entry so resume + inspect + compaction see the same
|
|
3993
|
+
* conversation the model saw, but intentionally:
|
|
3994
|
+
* - does NOT increment `turnCount` (a turn is a model response
|
|
3995
|
+
* this run produced, not historical context)
|
|
3996
|
+
* - does NOT log to `episodes` (avoid cross-run memory noise)
|
|
3997
|
+
*
|
|
3998
|
+
* Caller is responsible for validating role + content shape; this
|
|
3999
|
+
* helper just persists what it's given.
|
|
4000
|
+
*/
|
|
4001
|
+
async seedInitialMessage(role, text2) {
|
|
4002
|
+
const content = [{ type: "text", text: text2 }];
|
|
4003
|
+
this.messages.push({ role, content });
|
|
4004
|
+
await this.writeEntry({
|
|
4005
|
+
type: role,
|
|
4006
|
+
uuid: this.nextUuid(),
|
|
4007
|
+
parentUuid: this.lastUuid,
|
|
4008
|
+
ts: this.now(),
|
|
4009
|
+
message: { role, content }
|
|
4010
|
+
});
|
|
4011
|
+
}
|
|
3989
4012
|
async addAssistantMessage(content) {
|
|
3990
4013
|
this.messages.push({ role: "assistant", content });
|
|
3991
4014
|
await this.writeEntry({
|
|
@@ -8041,196 +8064,6 @@ function extractDescription(content) {
|
|
|
8041
8064
|
return headingText;
|
|
8042
8065
|
}
|
|
8043
8066
|
|
|
8044
|
-
// src/prompts/sections/base.ts
|
|
8045
|
-
init_cjs_shims();
|
|
8046
|
-
function getBaseSection() {
|
|
8047
|
-
return `# System
|
|
8048
|
-
|
|
8049
|
-
You are an AI assistant running inside la-machina-engine. You complete tasks by using the tools available to you. Your output goes to a programmatic caller (not a human terminal), so focus on correctness and completeness.
|
|
8050
|
-
|
|
8051
|
-
IMPORTANT: Assist with authorized security testing, defensive security, CTF challenges, and educational contexts. Refuse requests for destructive techniques, DoS attacks, mass targeting, supply chain compromise, or detection evasion for malicious purposes.
|
|
8052
|
-
IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident they are correct. You may use URLs provided in the task or discovered via tools.`;
|
|
8053
|
-
}
|
|
8054
|
-
|
|
8055
|
-
// src/prompts/sections/doingTasks.ts
|
|
8056
|
-
init_cjs_shims();
|
|
8057
|
-
function getDoingTasksSection() {
|
|
8058
|
-
return `# Doing tasks
|
|
8059
|
-
|
|
8060
|
-
- The caller will request you to perform tasks \u2014 solving bugs, adding features, refactoring, analyzing data, research, and more.
|
|
8061
|
-
- You are highly capable and often allow callers to complete ambitious tasks that would otherwise be too complex or take too long. You should defer to the caller's judgement about whether a task is too large to attempt.
|
|
8062
|
-
- If you notice the request is based on a misconception, or spot a bug adjacent to what was asked about, say so. You're a collaborator, not just an executor \u2014 callers benefit from your judgment, not just your compliance.
|
|
8063
|
-
- In general, do not propose changes to code you haven't read. If asked about or to modify a file, read it first. Understand existing code before suggesting modifications.
|
|
8064
|
-
- Do not create files unless they're absolutely necessary for achieving your goal. Generally prefer editing an existing file to creating a new one, as this prevents file bloat and builds on existing work more effectively.
|
|
8065
|
-
- Avoid giving time estimates or predictions for how long tasks will take. Focus on what needs to be done, not how long it might take.
|
|
8066
|
-
- If an approach fails, diagnose why before switching tactics \u2014 read the error, check your assumptions, try a focused fix. Don't retry the identical action blindly, but don't abandon a viable approach after a single failure either. Escalate only when you're genuinely stuck after investigation, not as a first response to friction.
|
|
8067
|
-
- Be careful not to introduce security vulnerabilities such as command injection, XSS, SQL injection, and other OWASP top 10 vulnerabilities. If you notice that you wrote insecure code, immediately fix it. Prioritize writing safe, secure, and correct code.
|
|
8068
|
-
- Don't add features, refactor code, or make "improvements" beyond what was asked. A bug fix doesn't need surrounding code cleaned up. A simple feature doesn't need extra configurability. Don't add docstrings, comments, or type annotations to code you didn't change. Only add comments where the logic isn't self-evident.
|
|
8069
|
-
- Don't add error handling, fallbacks, or validation for scenarios that can't happen. Trust internal code and framework guarantees. Only validate at system boundaries (user input, external APIs). Don't use feature flags or backwards-compatibility shims when you can just change the code.
|
|
8070
|
-
- Don't create helpers, utilities, or abstractions for one-time operations. Don't design for hypothetical future requirements. The right amount of complexity is what the task actually requires \u2014 no speculative abstractions, but no half-finished implementations either. Three similar lines of code is better than a premature abstraction.
|
|
8071
|
-
- Default to writing no comments. Only add one when the WHY is non-obvious: a hidden constraint, a subtle invariant, a workaround for a specific bug, behavior that would surprise a reader. If removing the comment wouldn't confuse a future reader, don't write it.
|
|
8072
|
-
- Don't explain WHAT the code does, since well-named identifiers already do that. Don't reference the current task, fix, or callers ("used by X", "added for the Y flow", "handles the case from issue #123"), since those belong in the commit message and rot as the codebase evolves.
|
|
8073
|
-
- Don't remove existing comments unless you're removing the code they describe or you know they're wrong. A comment that looks pointless to you may encode a constraint or a lesson from a past bug that isn't visible in the current diff.
|
|
8074
|
-
- Before reporting a task complete, verify it actually works: run the test, execute the script, check the output. Minimum complexity means no gold-plating, not skipping the finish line. If you can't verify (no test exists, can't run the code), say so explicitly rather than claiming success.
|
|
8075
|
-
- Report outcomes faithfully: if tests fail, say so with the relevant output; if you did not run a verification step, say that rather than implying it succeeded. Never claim "all tests pass" when output shows failures, never suppress or simplify failing checks to manufacture a green result, and never characterize incomplete or broken work as done. Equally, when a check did pass or a task is complete, state it plainly \u2014 do not hedge confirmed results with unnecessary disclaimers, downgrade finished work to "partial," or re-verify things you already checked. The goal is an accurate report, not a defensive one.`;
|
|
8076
|
-
}
|
|
8077
|
-
|
|
8078
|
-
// src/prompts/sections/actions.ts
|
|
8079
|
-
init_cjs_shims();
|
|
8080
|
-
function getActionsSection() {
|
|
8081
|
-
return `# Executing actions with care
|
|
8082
|
-
|
|
8083
|
-
Carefully consider the reversibility and blast radius of actions. Generally you can freely take local, reversible actions like editing files or running tests. But for actions that are hard to reverse, affect shared systems beyond your local environment, or could otherwise be risky or destructive, check with the caller before proceeding. The cost of pausing to confirm is low, while the cost of an unwanted action (lost work, unintended messages sent, deleted branches) can be very high. For actions like these, consider the context, the action, and caller instructions, and by default transparently communicate the action and ask for confirmation before proceeding. This default can be changed by caller instructions \u2014 if explicitly asked to operate more autonomously, then you may proceed without confirmation, but still attend to the risks and consequences when taking actions.
|
|
8084
|
-
|
|
8085
|
-
Examples of the kind of risky actions that warrant confirmation:
|
|
8086
|
-
- Destructive operations: deleting files/branches, dropping database tables, killing processes, rm -rf, overwriting uncommitted changes
|
|
8087
|
-
- Hard-to-reverse operations: force-pushing (can overwrite upstream), git reset --hard, amending published commits, removing or downgrading packages/dependencies, modifying CI/CD pipelines
|
|
8088
|
-
- Actions visible to others or that affect shared state: pushing code, creating/closing/commenting on PRs or issues, sending messages (Slack, email, GitHub), posting to external services, modifying shared infrastructure or permissions
|
|
8089
|
-
- Uploading content to third-party web tools (diagram renderers, pastebins, gists) publishes it \u2014 consider whether it could be sensitive before sending, since it may be cached or indexed even if later deleted.
|
|
8090
|
-
|
|
8091
|
-
When you encounter an obstacle, do not use destructive actions as a shortcut to simply make it go away. For instance, try to identify root causes and fix underlying issues rather than bypassing safety checks (e.g. --no-verify). If you discover unexpected state like unfamiliar files, branches, or configuration, investigate before deleting or overwriting, as it may represent in-progress work. For example, typically resolve merge conflicts rather than discarding changes; similarly, if a lock file exists, investigate what process holds it rather than deleting it. In short: only take risky actions carefully, and when in doubt, ask before acting. Follow both the spirit and letter of these instructions \u2014 measure twice, cut once.`;
|
|
8092
|
-
}
|
|
8093
|
-
|
|
8094
|
-
// src/prompts/sections/usingTools.ts
|
|
8095
|
-
init_cjs_shims();
|
|
8096
|
-
function getUsingToolsSection(options) {
|
|
8097
|
-
const has = (name) => options.registeredToolNames.has(name);
|
|
8098
|
-
const items = [];
|
|
8099
|
-
items.push(
|
|
8100
|
-
`Do NOT use Bash to run commands when a relevant dedicated tool is provided. Using dedicated tools produces clearer, more reviewable output. This is CRITICAL:`
|
|
8101
|
-
);
|
|
8102
|
-
if (has("Read")) items.push(` - To read files use Read instead of cat, head, tail, or sed`);
|
|
8103
|
-
if (has("Edit")) items.push(` - To edit files use Edit instead of sed or awk`);
|
|
8104
|
-
if (has("Write"))
|
|
8105
|
-
items.push(` - To create files use Write instead of cat with heredoc or echo redirection`);
|
|
8106
|
-
if (has("Glob")) items.push(` - To search for files use Glob instead of find or ls`);
|
|
8107
|
-
if (has("Grep")) items.push(` - To search the content of files, use Grep instead of grep or rg`);
|
|
8108
|
-
items.push(
|
|
8109
|
-
` - Reserve using Bash exclusively for system commands and terminal operations that require shell execution. If you are unsure and there is a relevant dedicated tool, default to using the dedicated tool and only fallback on Bash if it is absolutely necessary.`
|
|
8110
|
-
);
|
|
8111
|
-
items.push(
|
|
8112
|
-
`You can call multiple tools in a single response. If you intend to call multiple tools and there are no dependencies between them, make all independent tool calls in parallel. Maximize use of parallel tool calls where possible to increase efficiency. However, if some tool calls depend on previous calls to inform dependent values, do NOT call these tools in parallel and instead call them sequentially.`
|
|
8113
|
-
);
|
|
8114
|
-
if (has("Agent")) {
|
|
8115
|
-
items.push(
|
|
8116
|
-
`Use the Agent tool with specialized agents when the task at hand matches the agent's description. Subagents are valuable for parallelizing independent queries or for protecting the main context window from excessive results, but should not be used excessively when not needed. Importantly, avoid duplicating work that subagents are already doing \u2014 if you delegate research to a subagent, do not also perform the same searches yourself.`
|
|
8117
|
-
);
|
|
8118
|
-
if (has("Glob") || has("Grep")) {
|
|
8119
|
-
items.push(
|
|
8120
|
-
`For simple, directed codebase searches (e.g. for a specific file/class/function) use Glob or Grep directly.`
|
|
8121
|
-
);
|
|
8122
|
-
}
|
|
8123
|
-
}
|
|
8124
|
-
if (has("SkillPage")) {
|
|
8125
|
-
items.push(
|
|
8126
|
-
`Skills are surfaced in the system prompt. Use the SkillPage tool to load specific pages from multi-page skills when you need detailed instructions.`
|
|
8127
|
-
);
|
|
8128
|
-
}
|
|
8129
|
-
return `# Using your tools
|
|
8130
|
-
|
|
8131
|
-
${items.map((i) => ` - ${i}`).join("\n")}`;
|
|
8132
|
-
}
|
|
8133
|
-
|
|
8134
|
-
// src/prompts/sections/toneAndStyle.ts
|
|
8135
|
-
init_cjs_shims();
|
|
8136
|
-
function getToneAndStyleSection() {
|
|
8137
|
-
return `# Tone and style
|
|
8138
|
-
|
|
8139
|
-
- Only use emojis if the caller explicitly requests it. Avoid using emojis in all output unless asked.
|
|
8140
|
-
- Your responses should be concise and direct. Lead with the answer or action, not the reasoning.
|
|
8141
|
-
- When referencing specific functions or pieces of code include the pattern file_path:line_number.
|
|
8142
|
-
- When referencing GitHub issues or pull requests, use the owner/repo#123 format.
|
|
8143
|
-
- Do not use a colon before tool calls. Your tool calls may not be shown directly in the output, so text like "Let me read the file:" followed by a read tool call should just be "Let me read the file." with a period.
|
|
8144
|
-
|
|
8145
|
-
# Output efficiency
|
|
8146
|
-
|
|
8147
|
-
Go straight to the point. Try the simplest approach first without going in circles. Do not overdo it. Be extra concise.
|
|
8148
|
-
|
|
8149
|
-
Keep your text output brief and direct. Lead with the answer or action, not the reasoning. Skip filler words, preamble, and unnecessary transitions. Do not restate the task \u2014 just do it. When explaining, include only what is necessary.
|
|
8150
|
-
|
|
8151
|
-
Focus text output on:
|
|
8152
|
-
- Decisions that need input
|
|
8153
|
-
- High-level status updates at natural milestones
|
|
8154
|
-
- Errors or blockers that change the plan
|
|
8155
|
-
|
|
8156
|
-
If you can say it in one sentence, don't use three. Prefer short, direct sentences over long explanations.`;
|
|
8157
|
-
}
|
|
8158
|
-
|
|
8159
|
-
// src/prompts/sections/environment.ts
|
|
8160
|
-
init_cjs_shims();
|
|
8161
|
-
async function getEnvironmentSection(options) {
|
|
8162
|
-
let platform = "unknown";
|
|
8163
|
-
let osRelease = "";
|
|
8164
|
-
try {
|
|
8165
|
-
const os = await import("os");
|
|
8166
|
-
platform = os.platform();
|
|
8167
|
-
osRelease = os.release();
|
|
8168
|
-
} catch {
|
|
8169
|
-
platform = typeof navigator !== "undefined" ? "worker" : "unknown";
|
|
8170
|
-
}
|
|
8171
|
-
const shell = (typeof process !== "undefined" ? process.env?.SHELL : void 0) ?? (platform === "win32" ? "cmd.exe" : "/bin/sh");
|
|
8172
|
-
const osVersion = `${platform}${osRelease ? " " + osRelease : ""}`;
|
|
8173
|
-
const cwd = options.cwd ?? (typeof process !== "undefined" && process.cwd ? process.cwd() : "/");
|
|
8174
|
-
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
8175
|
-
const lines = [
|
|
8176
|
-
"# Environment",
|
|
8177
|
-
"",
|
|
8178
|
-
`- Platform: ${platform}`,
|
|
8179
|
-
`- Shell: ${shell}`,
|
|
8180
|
-
`- OS Version: ${osVersion}`,
|
|
8181
|
-
`- Working directory: ${cwd}`,
|
|
8182
|
-
`- Model: ${options.modelId} (provider: ${options.provider})`,
|
|
8183
|
-
`- Current date: ${date}`
|
|
8184
|
-
];
|
|
8185
|
-
if (canSpawnProcesses()) {
|
|
8186
|
-
const git = await getGitContext(cwd);
|
|
8187
|
-
if (git) {
|
|
8188
|
-
lines.push("");
|
|
8189
|
-
lines.push("## Git");
|
|
8190
|
-
if (git.branch) lines.push(`- Branch: ${git.branch}`);
|
|
8191
|
-
if (git.isRepo) lines.push(`- Is git repo: true`);
|
|
8192
|
-
if (git.status) lines.push(`- Status:
|
|
8193
|
-
${git.status}`);
|
|
8194
|
-
if (git.recentCommits) lines.push(`- Recent commits:
|
|
8195
|
-
${git.recentCommits}`);
|
|
8196
|
-
}
|
|
8197
|
-
}
|
|
8198
|
-
return lines.join("\n");
|
|
8199
|
-
}
|
|
8200
|
-
async function getGitContext(cwd) {
|
|
8201
|
-
try {
|
|
8202
|
-
const { execSync } = await import("child_process");
|
|
8203
|
-
const opts = {
|
|
8204
|
-
cwd,
|
|
8205
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
8206
|
-
timeout: 5e3
|
|
8207
|
-
};
|
|
8208
|
-
try {
|
|
8209
|
-
execSync("git rev-parse --is-inside-work-tree", opts);
|
|
8210
|
-
} catch {
|
|
8211
|
-
return null;
|
|
8212
|
-
}
|
|
8213
|
-
const branch = tryExec(execSync, "git branch --show-current", opts);
|
|
8214
|
-
const status = tryExec(execSync, "git status --short", opts, 2e3);
|
|
8215
|
-
const recentCommits = tryExec(execSync, "git log --oneline -5", opts, 2e3);
|
|
8216
|
-
const ctx = { isRepo: true };
|
|
8217
|
-
if (branch) ctx.branch = branch;
|
|
8218
|
-
if (status) ctx.status = status;
|
|
8219
|
-
if (recentCommits) ctx.recentCommits = recentCommits;
|
|
8220
|
-
return ctx;
|
|
8221
|
-
} catch {
|
|
8222
|
-
return null;
|
|
8223
|
-
}
|
|
8224
|
-
}
|
|
8225
|
-
function tryExec(execSync, cmd, opts, maxChars = 1e3) {
|
|
8226
|
-
try {
|
|
8227
|
-
const out = execSync(cmd, opts).toString("utf-8").trim();
|
|
8228
|
-
return out.length > maxChars ? out.slice(0, maxChars) + "\n...(truncated)" : out;
|
|
8229
|
-
} catch {
|
|
8230
|
-
return "";
|
|
8231
|
-
}
|
|
8232
|
-
}
|
|
8233
|
-
|
|
8234
8067
|
// src/prompts/sections/mcp.ts
|
|
8235
8068
|
init_cjs_shims();
|
|
8236
8069
|
function getMcpSection(options) {
|
|
@@ -8316,14 +8149,21 @@ function getApiServicesSection(opts) {
|
|
|
8316
8149
|
lines.push("");
|
|
8317
8150
|
}
|
|
8318
8151
|
} else {
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
|
|
8152
|
+
const hasDescribe = opts.hasDescribeService !== false;
|
|
8153
|
+
if (hasDescribe) {
|
|
8154
|
+
lines.push(
|
|
8155
|
+
"Configured external HTTP APIs. Use `ApiCall` to invoke, but first call `DescribeService(service)` to fetch that service's endpoint catalog. Auth is injected automatically."
|
|
8156
|
+
);
|
|
8157
|
+
} else {
|
|
8158
|
+
lines.push(
|
|
8159
|
+
"Configured external HTTP APIs. Use `ApiCall` to invoke. Auth is injected automatically."
|
|
8160
|
+
);
|
|
8161
|
+
}
|
|
8322
8162
|
lines.push("");
|
|
8323
8163
|
appendStrictApiToolRules(
|
|
8324
8164
|
lines,
|
|
8325
8165
|
/* hasLazy */
|
|
8326
|
-
|
|
8166
|
+
hasDescribe
|
|
8327
8167
|
);
|
|
8328
8168
|
for (const svc of withEndpoints) {
|
|
8329
8169
|
const count = svc.endpoints.length;
|
|
@@ -8378,33 +8218,20 @@ function resolveEffectiveMode(services, requested, threshold) {
|
|
|
8378
8218
|
// src/prompts/systemPrompt.ts
|
|
8379
8219
|
async function buildSystemPrompt(options) {
|
|
8380
8220
|
const sections = [];
|
|
8221
|
+
const visibleToolNames = options.visibleToolNames ?? /* @__PURE__ */ new Set();
|
|
8381
8222
|
if (options.coordinatorMode) {
|
|
8382
|
-
} else if (options.staticBase !== void 0 && options.staticBase.length > 0) {
|
|
8223
|
+
} else if (options.staticBase !== void 0 && options.staticBase.trim().length > 0) {
|
|
8383
8224
|
sections.push(options.staticBase);
|
|
8384
|
-
}
|
|
8385
|
-
sections.push(getBaseSection());
|
|
8386
|
-
sections.push(getDoingTasksSection());
|
|
8387
|
-
sections.push(getActionsSection());
|
|
8388
|
-
if (options.registeredToolNames !== void 0 && options.registeredToolNames.size > 0) {
|
|
8389
|
-
sections.push(getUsingToolsSection({ registeredToolNames: options.registeredToolNames }));
|
|
8390
|
-
}
|
|
8391
|
-
sections.push(getToneAndStyleSection());
|
|
8392
|
-
}
|
|
8393
|
-
sections.push(
|
|
8394
|
-
await getEnvironmentSection({
|
|
8395
|
-
modelId: options.modelId ?? "unknown",
|
|
8396
|
-
provider: options.provider ?? "unknown",
|
|
8397
|
-
cwd: options.cwd
|
|
8398
|
-
})
|
|
8399
|
-
);
|
|
8225
|
+
}
|
|
8400
8226
|
if (options.mcpTools !== void 0 && options.mcpTools.length > 0) {
|
|
8401
8227
|
const mcpSection = getMcpSection({ mcpTools: options.mcpTools });
|
|
8402
8228
|
if (mcpSection !== null) sections.push(mcpSection);
|
|
8403
8229
|
}
|
|
8404
|
-
if (options.apiServices !== void 0 && options.apiServices.length > 0) {
|
|
8230
|
+
if (options.apiServices !== void 0 && options.apiServices.length > 0 && visibleToolNames.has("ApiCall")) {
|
|
8405
8231
|
const apiSection = getApiServicesSection({
|
|
8406
8232
|
services: options.apiServices,
|
|
8407
8233
|
mode: options.apiCatalogMode ?? "lazy",
|
|
8234
|
+
hasDescribeService: visibleToolNames.has("DescribeService"),
|
|
8408
8235
|
...options.apiLazyTokenThreshold !== void 0 ? { lazyTokenThreshold: options.apiLazyTokenThreshold } : {}
|
|
8409
8236
|
});
|
|
8410
8237
|
if (apiSection !== null) sections.push(apiSection);
|
|
@@ -8425,7 +8252,7 @@ ${rules}`);
|
|
|
8425
8252
|
${lessons}`);
|
|
8426
8253
|
}
|
|
8427
8254
|
const effectiveSkillList = options.skillList !== void 0 ? options.skillList : options.skillsAutoload ? await collectSkills(options.storage, options.skillsDir ?? "skills") : void 0;
|
|
8428
|
-
if (effectiveSkillList !== void 0 && effectiveSkillList.length > 0) {
|
|
8255
|
+
if (effectiveSkillList !== void 0 && effectiveSkillList.length > 0 && visibleToolNames.has("SkillPage")) {
|
|
8429
8256
|
const lines = ["# Skills"];
|
|
8430
8257
|
for (const skill of effectiveSkillList) {
|
|
8431
8258
|
lines.push(`- ${skill.name}: ${skill.description}`);
|
|
@@ -10847,6 +10674,18 @@ function scrubRunOptions(opts) {
|
|
|
10847
10674
|
if (opts.tools !== void 0) out.tools = [...opts.tools];
|
|
10848
10675
|
if (opts.toolChoice !== void 0) out.toolChoice = opts.toolChoice;
|
|
10849
10676
|
if (opts.tokenBudget !== void 0) out.tokenBudget = opts.tokenBudget;
|
|
10677
|
+
if (opts.systemPromptBase !== void 0 && opts.systemPromptBase.length > 0) {
|
|
10678
|
+
out.systemPromptBase = {
|
|
10679
|
+
present: true,
|
|
10680
|
+
chars: opts.systemPromptBase.length
|
|
10681
|
+
};
|
|
10682
|
+
}
|
|
10683
|
+
if (opts.systemPromptAppend !== void 0 && opts.systemPromptAppend.length > 0) {
|
|
10684
|
+
out.systemPromptAppend = {
|
|
10685
|
+
present: true,
|
|
10686
|
+
chars: opts.systemPromptAppend.length
|
|
10687
|
+
};
|
|
10688
|
+
}
|
|
10850
10689
|
if (opts.knowledge !== void 0) {
|
|
10851
10690
|
const k = {};
|
|
10852
10691
|
if (opts.knowledge.folders !== void 0) k.folders = [...opts.knowledge.folders];
|
|
@@ -10879,6 +10718,24 @@ function scrubRunOptions(opts) {
|
|
|
10879
10718
|
}
|
|
10880
10719
|
if (opts.compaction !== void 0) out.compaction = opts.compaction;
|
|
10881
10720
|
if (opts.context !== void 0) out.context = { ...opts.context };
|
|
10721
|
+
if (opts.initialMessages !== void 0 && Array.isArray(opts.initialMessages)) {
|
|
10722
|
+
const roles = [];
|
|
10723
|
+
let totalChars = 0;
|
|
10724
|
+
for (const m of opts.initialMessages) {
|
|
10725
|
+
if (m === null || typeof m !== "object") continue;
|
|
10726
|
+
const role = m.role;
|
|
10727
|
+
const content = m.content;
|
|
10728
|
+
if (role !== "user" && role !== "assistant") continue;
|
|
10729
|
+
if (typeof content !== "string") continue;
|
|
10730
|
+
roles.push(role);
|
|
10731
|
+
totalChars += content.length;
|
|
10732
|
+
}
|
|
10733
|
+
out.initialMessages = {
|
|
10734
|
+
count: roles.length,
|
|
10735
|
+
roles,
|
|
10736
|
+
totalChars
|
|
10737
|
+
};
|
|
10738
|
+
}
|
|
10882
10739
|
return out;
|
|
10883
10740
|
}
|
|
10884
10741
|
function serializeOutputSchema(schema) {
|
|
@@ -10954,6 +10811,14 @@ function rebuildMessagesFromEntries(entries) {
|
|
|
10954
10811
|
return messages;
|
|
10955
10812
|
}
|
|
10956
10813
|
|
|
10814
|
+
// src/engine/types.ts
|
|
10815
|
+
init_cjs_shims();
|
|
10816
|
+
var INITIAL_MESSAGES_LIMITS = {
|
|
10817
|
+
maxMessages: 100,
|
|
10818
|
+
maxTotalChars: 32e3,
|
|
10819
|
+
maxCharsPerMessage: 8e3
|
|
10820
|
+
};
|
|
10821
|
+
|
|
10957
10822
|
// src/engine/response.ts
|
|
10958
10823
|
init_cjs_shims();
|
|
10959
10824
|
function toResponse(result, extra) {
|
|
@@ -11344,60 +11209,36 @@ var Engine = class {
|
|
|
11344
11209
|
const memory = createSmartMemory({ storage, config: this.config.memory });
|
|
11345
11210
|
const agents = await this.resolveAgents(storage);
|
|
11346
11211
|
const mcpTools = await this.mcpManager.getTools();
|
|
11347
|
-
const toolNameSet = this.collectToolNames(mcpTools);
|
|
11348
11212
|
const coordinatorBase = isCoordinatorMode(this.config) ? getCoordinatorBasePrompt() : void 0;
|
|
11349
11213
|
const skillSource = this.resolveSkillSource(options.skills, storage);
|
|
11350
11214
|
const skillList = skillSource !== void 0 ? await skillSource.list() : void 0;
|
|
11351
11215
|
const apiConfig = this.resolveApiConfig(options.api);
|
|
11352
11216
|
const offloadConfig = this.resolveOffloadConfig(options.compaction?.toolResultOffload);
|
|
11353
11217
|
const knowledgeRuntime = this.resolveKnowledgeRuntime(options.knowledge, storage);
|
|
11354
|
-
let systemPrompt = await buildSystemPrompt({
|
|
11355
|
-
...coordinatorBase !== void 0 ? { base: coordinatorBase } : {},
|
|
11356
|
-
...options.systemPromptBase !== void 0 ? { staticBase: options.systemPromptBase } : {},
|
|
11357
|
-
...options.systemPromptAppend !== void 0 && options.systemPromptAppend.length > 0 ? { platformAppend: options.systemPromptAppend } : {},
|
|
11358
|
-
memory,
|
|
11359
|
-
storage,
|
|
11360
|
-
// When an override was supplied, skip the legacy disk-scan path.
|
|
11361
|
-
skillsAutoload: options.skills !== void 0 ? false : this.config.skills.autoload,
|
|
11362
|
-
...this.config.skills.path !== void 0 ? { skillsDir: this.config.skills.path } : {},
|
|
11363
|
-
...skillList !== void 0 ? { skillList } : {},
|
|
11364
|
-
modelId: this.config.model.modelId,
|
|
11365
|
-
provider: this.config.model.provider,
|
|
11366
|
-
registeredToolNames: toolNameSet,
|
|
11367
|
-
mcpTools,
|
|
11368
|
-
coordinatorMode: isCoordinatorMode(this.config),
|
|
11369
|
-
// Plan 047 — render API services catalog (lazy by default).
|
|
11370
|
-
...apiConfig !== void 0 && apiConfig.services.length > 0 ? {
|
|
11371
|
-
apiServices: apiConfig.services,
|
|
11372
|
-
apiCatalogMode: apiConfig.mode ?? "lazy",
|
|
11373
|
-
...apiConfig.lazyTokenThreshold !== void 0 ? { apiLazyTokenThreshold: apiConfig.lazyTokenThreshold } : {}
|
|
11374
|
-
} : {}
|
|
11375
|
-
});
|
|
11376
|
-
if (options.outputFormat === "json") {
|
|
11377
|
-
systemPrompt += "\n\n" + buildSchemaPrompt(options.outputSchema);
|
|
11378
|
-
}
|
|
11379
11218
|
const gate = this.resolveGate();
|
|
11380
11219
|
const inspect = this.buildInspectWriter(storage.workspace, logPath);
|
|
11381
|
-
const registry =
|
|
11382
|
-
|
|
11220
|
+
const { systemPrompt: assembledPrompt, registry } = await this.buildPromptAndRegistry({
|
|
11221
|
+
runOptions: options,
|
|
11222
|
+
coordinatorBase,
|
|
11383
11223
|
storage,
|
|
11384
11224
|
client,
|
|
11385
|
-
|
|
11386
|
-
parentAgentId: null,
|
|
11225
|
+
logPath,
|
|
11387
11226
|
subagentRegistry,
|
|
11388
|
-
system: systemPrompt,
|
|
11389
11227
|
agents,
|
|
11390
11228
|
mcpTools,
|
|
11391
11229
|
memory,
|
|
11392
11230
|
inspect,
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
|
|
11398
|
-
|
|
11231
|
+
gate,
|
|
11232
|
+
skillSource,
|
|
11233
|
+
skillList,
|
|
11234
|
+
apiConfig,
|
|
11235
|
+
offloadConfig,
|
|
11236
|
+
knowledgeRuntime
|
|
11399
11237
|
});
|
|
11400
|
-
|
|
11238
|
+
let systemPrompt = assembledPrompt;
|
|
11239
|
+
if (options.outputFormat === "json") {
|
|
11240
|
+
systemPrompt += "\n\n" + buildSchemaPrompt(options.outputSchema);
|
|
11241
|
+
}
|
|
11401
11242
|
await inspect.writeStartSnapshot({
|
|
11402
11243
|
systemPrompt,
|
|
11403
11244
|
tools: this.snapshotTools(registry, mcpTools),
|
|
@@ -11456,6 +11297,23 @@ var Engine = class {
|
|
|
11456
11297
|
const runTimeout = this.startRunTimeout();
|
|
11457
11298
|
try {
|
|
11458
11299
|
await writer.setStatus("running");
|
|
11300
|
+
if (options.initialMessages !== void 0) {
|
|
11301
|
+
const validation = validateInitialMessages(options.initialMessages);
|
|
11302
|
+
if (!validation.ok) {
|
|
11303
|
+
await writer.setStatus("failed");
|
|
11304
|
+
return {
|
|
11305
|
+
runId,
|
|
11306
|
+
status: "failed",
|
|
11307
|
+
data: null,
|
|
11308
|
+
meta: { nodeId: options.nodeId, durationMs: Date.now() - startTime },
|
|
11309
|
+
errors: [{ code: "ERR_INVALID_INITIAL_MESSAGES", message: validation.message }],
|
|
11310
|
+
timestamp: Date.now()
|
|
11311
|
+
};
|
|
11312
|
+
}
|
|
11313
|
+
for (const m of validation.messages) {
|
|
11314
|
+
await ctx.seedInitialMessage(m.role, m.content);
|
|
11315
|
+
}
|
|
11316
|
+
}
|
|
11459
11317
|
await dispatchHooks(this.config.hooks.preRun, {
|
|
11460
11318
|
runId,
|
|
11461
11319
|
nodeId: options.nodeId,
|
|
@@ -11549,68 +11407,55 @@ var Engine = class {
|
|
|
11549
11407
|
const memory = createSmartMemory({ storage, config: this.config.memory });
|
|
11550
11408
|
const agents = await this.resolveAgents(storage);
|
|
11551
11409
|
const mcpTools = await this.mcpManager.getTools();
|
|
11552
|
-
const toolNameSet = this.collectToolNames(mcpTools);
|
|
11553
11410
|
const coordinatorBase = isCoordinatorMode(this.config) ? getCoordinatorBasePrompt() : void 0;
|
|
11554
11411
|
const skillSource = this.resolveSkillSource(options.skills, storage);
|
|
11555
11412
|
const skillList = skillSource !== void 0 ? await skillSource.list() : void 0;
|
|
11556
11413
|
const apiConfig = this.resolveApiConfig(options.api);
|
|
11557
11414
|
const offloadConfig = this.resolveOffloadConfig(options.compaction?.toolResultOffload);
|
|
11558
11415
|
const knowledgeRuntime = this.resolveKnowledgeRuntime(options.knowledge, storage);
|
|
11559
|
-
let systemPrompt = await buildSystemPrompt({
|
|
11560
|
-
...coordinatorBase !== void 0 ? { base: coordinatorBase } : {},
|
|
11561
|
-
...options.systemPromptBase !== void 0 ? { staticBase: options.systemPromptBase } : {},
|
|
11562
|
-
...options.systemPromptAppend !== void 0 && options.systemPromptAppend.length > 0 ? { platformAppend: options.systemPromptAppend } : {},
|
|
11563
|
-
memory,
|
|
11564
|
-
storage,
|
|
11565
|
-
// When an override was supplied, skip the legacy disk-scan path.
|
|
11566
|
-
skillsAutoload: options.skills !== void 0 ? false : this.config.skills.autoload,
|
|
11567
|
-
...this.config.skills.path !== void 0 ? { skillsDir: this.config.skills.path } : {},
|
|
11568
|
-
...skillList !== void 0 ? { skillList } : {},
|
|
11569
|
-
modelId: this.config.model.modelId,
|
|
11570
|
-
provider: this.config.model.provider,
|
|
11571
|
-
registeredToolNames: toolNameSet,
|
|
11572
|
-
mcpTools,
|
|
11573
|
-
coordinatorMode: isCoordinatorMode(this.config),
|
|
11574
|
-
// Plan 047 — render API services catalog (lazy by default).
|
|
11575
|
-
...apiConfig !== void 0 && apiConfig.services.length > 0 ? {
|
|
11576
|
-
apiServices: apiConfig.services,
|
|
11577
|
-
apiCatalogMode: apiConfig.mode ?? "lazy",
|
|
11578
|
-
...apiConfig.lazyTokenThreshold !== void 0 ? { apiLazyTokenThreshold: apiConfig.lazyTokenThreshold } : {}
|
|
11579
|
-
} : {}
|
|
11580
|
-
});
|
|
11581
|
-
if (options.outputFormat === "json") {
|
|
11582
|
-
systemPrompt += "\n\n" + buildSchemaPrompt(options.outputSchema);
|
|
11583
|
-
}
|
|
11584
11416
|
const gate = this.resolveGate();
|
|
11585
11417
|
const inspect = this.buildInspectWriter(storage.workspace, logPath);
|
|
11586
|
-
const registry =
|
|
11587
|
-
|
|
11418
|
+
const { systemPrompt: assembledPrompt, registry } = await this.buildPromptAndRegistry({
|
|
11419
|
+
runOptions: options,
|
|
11420
|
+
coordinatorBase,
|
|
11588
11421
|
storage,
|
|
11589
11422
|
client,
|
|
11590
|
-
|
|
11591
|
-
parentAgentId: null,
|
|
11423
|
+
logPath,
|
|
11592
11424
|
subagentRegistry,
|
|
11593
|
-
system: systemPrompt,
|
|
11594
11425
|
agents,
|
|
11595
11426
|
mcpTools,
|
|
11596
11427
|
memory,
|
|
11597
11428
|
inspect,
|
|
11598
|
-
|
|
11599
|
-
|
|
11600
|
-
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
|
|
11429
|
+
gate,
|
|
11430
|
+
skillSource,
|
|
11431
|
+
skillList,
|
|
11432
|
+
apiConfig,
|
|
11433
|
+
offloadConfig,
|
|
11434
|
+
knowledgeRuntime
|
|
11604
11435
|
});
|
|
11436
|
+
let systemPrompt = assembledPrompt;
|
|
11437
|
+
if (options.outputFormat === "json") {
|
|
11438
|
+
systemPrompt += "\n\n" + buildSchemaPrompt(options.outputSchema);
|
|
11439
|
+
}
|
|
11605
11440
|
await inspect.writeStartSnapshot({
|
|
11606
11441
|
systemPrompt,
|
|
11607
11442
|
tools: this.snapshotTools(registry, mcpTools),
|
|
11443
|
+
// Plan 052 review fix — surface the resume-time effective
|
|
11444
|
+
// policy in `run-options.json` so post-hoc debuggers see
|
|
11445
|
+
// exactly what gating drove the resume's prompt + tool
|
|
11446
|
+
// surface. Otherwise resume's inspect bundle looked like a
|
|
11447
|
+
// fresh run with no restrictions, masking the silent-widening
|
|
11448
|
+
// failure mode documented on `ResumeOptions.tools`.
|
|
11608
11449
|
runOptions: scrubRunOptions({
|
|
11609
11450
|
runId: snapshot.runId,
|
|
11610
11451
|
nodeId: snapshot.nodeId,
|
|
11611
11452
|
task: "[resumed run \u2014 original task in transcript]",
|
|
11612
11453
|
...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
|
|
11613
|
-
...options.outputSchema !== void 0 ? { outputSchema: options.outputSchema } : {}
|
|
11454
|
+
...options.outputSchema !== void 0 ? { outputSchema: options.outputSchema } : {},
|
|
11455
|
+
...options.tools !== void 0 ? { tools: options.tools } : {},
|
|
11456
|
+
...options.toolChoice !== void 0 ? { toolChoice: options.toolChoice } : {},
|
|
11457
|
+
...options.systemPromptBase !== void 0 ? { systemPromptBase: options.systemPromptBase } : {},
|
|
11458
|
+
...options.systemPromptAppend !== void 0 ? { systemPromptAppend: options.systemPromptAppend } : {}
|
|
11614
11459
|
}),
|
|
11615
11460
|
modelConfig: scrubModelConfig(
|
|
11616
11461
|
{
|
|
@@ -12259,72 +12104,97 @@ ${inputJson}
|
|
|
12259
12104
|
});
|
|
12260
12105
|
}
|
|
12261
12106
|
/**
|
|
12262
|
-
*
|
|
12263
|
-
*
|
|
12264
|
-
*
|
|
12265
|
-
*
|
|
12266
|
-
*
|
|
12107
|
+
* Plan 052 — two-pass system-prompt + tool-registry build.
|
|
12108
|
+
*
|
|
12109
|
+
* The prompt's API / skill / MCP sections describe only the tools
|
|
12110
|
+
* the model will actually see, so we must know the post-filter
|
|
12111
|
+
* tool set before assembling the prompt. The registry, however,
|
|
12112
|
+
* is what produces that set, AND its `Agent` tool needs the
|
|
12113
|
+
* final system prompt baked in for subagent dispatch.
|
|
12114
|
+
*
|
|
12115
|
+
* The chicken-and-egg is resolved by building twice:
|
|
12116
|
+
*
|
|
12117
|
+
* Pass 1 — placeholder prompt → registry → applyRunToolFilter
|
|
12118
|
+
* → snapshot of visible tool names + visible MCP tools.
|
|
12119
|
+
* Pass 2 — final prompt assembled from those visible surfaces
|
|
12120
|
+
* → rebuild registry → applyRunToolFilter again.
|
|
12121
|
+
*
|
|
12122
|
+
* `applyRunToolFilter` is deterministic given options, so the
|
|
12123
|
+
* second filter pass is identical to the first; the second
|
|
12124
|
+
* registry is the authoritative one returned to the caller.
|
|
12125
|
+
*
|
|
12126
|
+
* Pass 1's prompt is intentionally minimal (placeholder string)
|
|
12127
|
+
* because the only thing we use the first registry for is its
|
|
12128
|
+
* post-filter tool list. The transient prompt never reaches the
|
|
12129
|
+
* model.
|
|
12267
12130
|
*/
|
|
12268
|
-
|
|
12269
|
-
const
|
|
12270
|
-
|
|
12271
|
-
|
|
12272
|
-
|
|
12273
|
-
|
|
12274
|
-
|
|
12275
|
-
|
|
12276
|
-
|
|
12277
|
-
|
|
12278
|
-
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
|
|
12287
|
-
|
|
12288
|
-
|
|
12289
|
-
|
|
12290
|
-
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
|
|
12295
|
-
|
|
12296
|
-
|
|
12297
|
-
|
|
12298
|
-
|
|
12299
|
-
|
|
12300
|
-
|
|
12301
|
-
|
|
12302
|
-
|
|
12303
|
-
|
|
12304
|
-
|
|
12305
|
-
|
|
12306
|
-
|
|
12307
|
-
|
|
12308
|
-
|
|
12309
|
-
|
|
12310
|
-
}
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
|
|
12318
|
-
}
|
|
12319
|
-
|
|
12320
|
-
|
|
12321
|
-
|
|
12322
|
-
|
|
12323
|
-
|
|
12324
|
-
|
|
12325
|
-
|
|
12326
|
-
|
|
12327
|
-
|
|
12131
|
+
async buildPromptAndRegistry(args) {
|
|
12132
|
+
const {
|
|
12133
|
+
runOptions,
|
|
12134
|
+
coordinatorBase,
|
|
12135
|
+
storage,
|
|
12136
|
+
client,
|
|
12137
|
+
logPath,
|
|
12138
|
+
subagentRegistry,
|
|
12139
|
+
agents,
|
|
12140
|
+
mcpTools,
|
|
12141
|
+
memory,
|
|
12142
|
+
inspect,
|
|
12143
|
+
gate,
|
|
12144
|
+
skillSource,
|
|
12145
|
+
skillList,
|
|
12146
|
+
apiConfig,
|
|
12147
|
+
offloadConfig,
|
|
12148
|
+
knowledgeRuntime
|
|
12149
|
+
} = args;
|
|
12150
|
+
const baseRegistryArgs = {
|
|
12151
|
+
config: this.config,
|
|
12152
|
+
storage,
|
|
12153
|
+
client,
|
|
12154
|
+
parentLogPath: logPath,
|
|
12155
|
+
parentAgentId: null,
|
|
12156
|
+
subagentRegistry,
|
|
12157
|
+
agents,
|
|
12158
|
+
mcpTools,
|
|
12159
|
+
memory,
|
|
12160
|
+
inspect,
|
|
12161
|
+
...this.config.hooks.propagateGateToSubagents === true && gate !== void 0 ? { subagentGate: gate } : {},
|
|
12162
|
+
...skillSource !== void 0 ? { skillSource } : {},
|
|
12163
|
+
...apiConfig !== void 0 ? { apiConfig } : {},
|
|
12164
|
+
...offloadConfig !== void 0 ? { toolResultOffload: offloadConfig } : {},
|
|
12165
|
+
...knowledgeRuntime !== void 0 ? { knowledge: knowledgeRuntime } : {},
|
|
12166
|
+
...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
|
|
12167
|
+
};
|
|
12168
|
+
const tempRegistry = buildToolRegistry({ ...baseRegistryArgs, system: "" });
|
|
12169
|
+
applyRunToolFilter(tempRegistry, runOptions);
|
|
12170
|
+
const visibleToolNames = new Set(tempRegistry.list().map((t) => t.name));
|
|
12171
|
+
const visibleMcpTools = mcpTools.filter((t) => visibleToolNames.has(t.name));
|
|
12172
|
+
const systemPrompt = await buildSystemPrompt({
|
|
12173
|
+
...coordinatorBase !== void 0 ? { base: coordinatorBase } : {},
|
|
12174
|
+
...runOptions.systemPromptBase !== void 0 ? { staticBase: runOptions.systemPromptBase } : {},
|
|
12175
|
+
...runOptions.systemPromptAppend !== void 0 && runOptions.systemPromptAppend.length > 0 ? { platformAppend: runOptions.systemPromptAppend } : {},
|
|
12176
|
+
memory,
|
|
12177
|
+
storage,
|
|
12178
|
+
// When an override was supplied, skip the legacy disk-scan path.
|
|
12179
|
+
skillsAutoload: skillSource !== void 0 ? false : this.config.skills.autoload,
|
|
12180
|
+
...this.config.skills.path !== void 0 ? { skillsDir: this.config.skills.path } : {},
|
|
12181
|
+
...skillList !== void 0 ? { skillList } : {},
|
|
12182
|
+
// Plan 052 — pass the FINAL post-filter visible tool surface
|
|
12183
|
+
// so prompt sections gate correctly.
|
|
12184
|
+
visibleToolNames,
|
|
12185
|
+
mcpTools: visibleMcpTools,
|
|
12186
|
+
coordinatorMode: isCoordinatorMode(this.config),
|
|
12187
|
+
// Plan 047 — render API services catalog (lazy by default).
|
|
12188
|
+
// Gating on `ApiCall` visibility lives inside buildSystemPrompt.
|
|
12189
|
+
...apiConfig !== void 0 && apiConfig.services.length > 0 ? {
|
|
12190
|
+
apiServices: apiConfig.services,
|
|
12191
|
+
apiCatalogMode: apiConfig.mode ?? "lazy",
|
|
12192
|
+
...apiConfig.lazyTokenThreshold !== void 0 ? { apiLazyTokenThreshold: apiConfig.lazyTokenThreshold } : {}
|
|
12193
|
+
} : {}
|
|
12194
|
+
});
|
|
12195
|
+
const registry = buildToolRegistry({ ...baseRegistryArgs, system: systemPrompt });
|
|
12196
|
+
applyRunToolFilter(registry, runOptions);
|
|
12197
|
+
return { systemPrompt, registry };
|
|
12328
12198
|
}
|
|
12329
12199
|
/**
|
|
12330
12200
|
* Resolve the subagent catalogue the Agent tool will dispatch against.
|
|
@@ -12962,6 +12832,60 @@ function buildToolRegistry(options) {
|
|
|
12962
12832
|
}
|
|
12963
12833
|
return registry;
|
|
12964
12834
|
}
|
|
12835
|
+
function validateInitialMessages(raw) {
|
|
12836
|
+
if (!Array.isArray(raw)) {
|
|
12837
|
+
return { ok: false, message: "initialMessages must be an array" };
|
|
12838
|
+
}
|
|
12839
|
+
const { maxMessages, maxTotalChars, maxCharsPerMessage } = INITIAL_MESSAGES_LIMITS;
|
|
12840
|
+
if (raw.length > maxMessages) {
|
|
12841
|
+
return {
|
|
12842
|
+
ok: false,
|
|
12843
|
+
message: `initialMessages exceeds max of ${String(maxMessages)} messages (got ${String(raw.length)})`
|
|
12844
|
+
};
|
|
12845
|
+
}
|
|
12846
|
+
const out = [];
|
|
12847
|
+
let totalChars = 0;
|
|
12848
|
+
for (let i = 0; i < raw.length; i++) {
|
|
12849
|
+
const m = raw[i];
|
|
12850
|
+
if (m === null || typeof m !== "object") {
|
|
12851
|
+
return { ok: false, message: `initialMessages[${String(i)}] must be an object` };
|
|
12852
|
+
}
|
|
12853
|
+
if (m.role !== "user" && m.role !== "assistant") {
|
|
12854
|
+
return {
|
|
12855
|
+
ok: false,
|
|
12856
|
+
message: `initialMessages[${String(i)}].role must be 'user' or 'assistant'`
|
|
12857
|
+
};
|
|
12858
|
+
}
|
|
12859
|
+
if (typeof m.content !== "string") {
|
|
12860
|
+
return {
|
|
12861
|
+
ok: false,
|
|
12862
|
+
message: `initialMessages[${String(i)}].content must be a string`
|
|
12863
|
+
};
|
|
12864
|
+
}
|
|
12865
|
+
const trimmed = m.content.trim();
|
|
12866
|
+
if (trimmed.length === 0) {
|
|
12867
|
+
return {
|
|
12868
|
+
ok: false,
|
|
12869
|
+
message: `initialMessages[${String(i)}].content must not be empty`
|
|
12870
|
+
};
|
|
12871
|
+
}
|
|
12872
|
+
if (trimmed.length > maxCharsPerMessage) {
|
|
12873
|
+
return {
|
|
12874
|
+
ok: false,
|
|
12875
|
+
message: `initialMessages[${String(i)}].content exceeds ${String(maxCharsPerMessage)} chars`
|
|
12876
|
+
};
|
|
12877
|
+
}
|
|
12878
|
+
totalChars += trimmed.length;
|
|
12879
|
+
if (totalChars > maxTotalChars) {
|
|
12880
|
+
return {
|
|
12881
|
+
ok: false,
|
|
12882
|
+
message: `initialMessages total content exceeds ${String(maxTotalChars)} chars`
|
|
12883
|
+
};
|
|
12884
|
+
}
|
|
12885
|
+
out.push({ role: m.role, content: trimmed });
|
|
12886
|
+
}
|
|
12887
|
+
return { ok: true, messages: out };
|
|
12888
|
+
}
|
|
12965
12889
|
|
|
12966
12890
|
// src/index.ts
|
|
12967
12891
|
init_contract();
|