@letta-ai/letta-code 0.33.4 → 0.33.5
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/mcp-client.js +2 -2
- package/dist/mcp-client.js.map +1 -1
- package/dist/types/agent/subagents/names.d.ts +1 -1
- package/dist/types/agent/subagents/names.d.ts.map +1 -1
- package/dist/types/tools/impl/workflow.d.ts.map +1 -1
- package/dist/types/tools/workflow/decide.d.ts +32 -0
- package/dist/types/tools/workflow/decide.d.ts.map +1 -0
- package/dist/types/tools/workflow/execution-registry.d.ts.map +1 -1
- package/dist/types/tools/workflow/journal.d.ts +15 -2
- package/dist/types/tools/workflow/journal.d.ts.map +1 -1
- package/dist/types/tools/workflow/sdk-loader.d.ts +3 -0
- package/dist/types/tools/workflow/sdk-loader.d.ts.map +1 -1
- package/dist/types/tools/workflow/sdk-spawner.d.ts +17 -0
- package/dist/types/tools/workflow/sdk-spawner.d.ts.map +1 -1
- package/dist/types/tools/workflow/types.d.ts +13 -3
- package/dist/types/tools/workflow/types.d.ts.map +1 -1
- package/dist/types/tools/workflow/workflow-engine.d.ts +1 -1
- package/dist/types/tools/workflow/workflow-engine.d.ts.map +1 -1
- package/letta.js +369 -81
- package/package.json +2 -2
- package/skills/workflow-authoring/SKILL.md +31 -4
package/letta.js
CHANGED
|
@@ -5653,7 +5653,7 @@ var package_default;
|
|
|
5653
5653
|
var init_package = __esm(() => {
|
|
5654
5654
|
package_default = {
|
|
5655
5655
|
name: "@letta-ai/letta-code",
|
|
5656
|
-
version: "0.33.
|
|
5656
|
+
version: "0.33.5",
|
|
5657
5657
|
lettaStartupLogProtocol: 1,
|
|
5658
5658
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
5659
5659
|
type: "module",
|
|
@@ -5785,7 +5785,7 @@ var init_package = __esm(() => {
|
|
|
5785
5785
|
dependencies: {
|
|
5786
5786
|
"@earendil-works/pi-ai": "^0.87.1",
|
|
5787
5787
|
"@janhapke/sharp-electron": "0.35.3-electron.1",
|
|
5788
|
-
"@letta-ai/letta-agent-sdk": "
|
|
5788
|
+
"@letta-ai/letta-agent-sdk": "0.8.21",
|
|
5789
5789
|
"@letta-ai/letta-client": "^1.10.2",
|
|
5790
5790
|
"@letta-ai/trajectory": "0.2.0",
|
|
5791
5791
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
@@ -111416,7 +111416,6 @@ var init_names = __esm(() => {
|
|
|
111416
111416
|
"Songbird",
|
|
111417
111417
|
"Slider",
|
|
111418
111418
|
"Aguilar",
|
|
111419
|
-
"Dogmeat",
|
|
111420
111419
|
"Codsworth",
|
|
111421
111420
|
"Nick Valentine",
|
|
111422
111421
|
"Yes Man",
|
|
@@ -203018,40 +203017,31 @@ Pass a URL ending at the PR number, such as \`https://github.com/owner/repo/pull
|
|
|
203018
203017
|
var init_WatchPR = () => {};
|
|
203019
203018
|
|
|
203020
203019
|
// src/tools/descriptions/Workflow.md
|
|
203021
|
-
var Workflow_default = `Execute a workflow script that orchestrates multiple subagents deterministically
|
|
203020
|
+
var Workflow_default = `Execute a workflow script that orchestrates multiple subagents deterministically (loops, conditionals, fan-out) rather than model-driven.
|
|
203022
203021
|
|
|
203023
|
-
Workflows run in the background
|
|
203022
|
+
Workflows run in the background: this tool returns immediately with a task ID, and a <task-notification> carrying the script's return value arrives when the workflow completes. Do not poll or sleep for it, and never fabricate the result before it arrives. TaskStop aborts the run.
|
|
203024
203023
|
|
|
203025
|
-
ONLY call this tool when the user has explicitly opted into multi-agent orchestration
|
|
203024
|
+
ONLY call this tool when the user has explicitly opted into multi-agent orchestration — they asked for a workflow or multi-agent orchestration in their own words ("use a workflow", "fan out agents"), or invoked a skill whose instructions call this tool. Workflows can spawn many subagents and cost real money. For any other task, even one that would benefit from parallelism, describe what a workflow could do and ask first.
|
|
203026
203025
|
|
|
203027
|
-
|
|
203028
|
-
|
|
203029
|
-
The canonical multi-stage pattern — pipeline by default, each item verifies as soon as its review completes:
|
|
203026
|
+
Scripts are plain JavaScript and must begin with \`export const meta = {...}\`, a pure literal (no variables, calls, or interpolation). Pass the work list via \`args\`. Prefer \`pipeline()\` so each item moves to its next stage as soon as it is ready; \`agent()\` resolves to \`null\` on failure, so guard and filter:
|
|
203030
203027
|
|
|
203031
203028
|
export const meta = {
|
|
203032
|
-
name: 'review-
|
|
203033
|
-
description: 'Review
|
|
203029
|
+
name: 'review-files',
|
|
203030
|
+
description: 'Review each file for bugs, verify each finding',
|
|
203034
203031
|
phases: [{ title: 'Review' }, { title: 'Verify' }],
|
|
203035
203032
|
}
|
|
203036
|
-
const
|
|
203037
|
-
const
|
|
203038
|
-
const verdictSchema = {type: 'object', properties: {real: {type: 'boolean'}, why: {type: 'string'}}, required: ['real', 'why']}
|
|
203033
|
+
const findings = {type: 'object', properties: {bugs: {type: 'array', items: {type: 'string'}}}, required: ['bugs']}
|
|
203034
|
+
const verdict = {type: 'object', properties: {real: {type: 'boolean'}}, required: ['real']}
|
|
203039
203035
|
const results = await pipeline(
|
|
203040
|
-
|
|
203041
|
-
|
|
203042
|
-
review => review
|
|
203043
|
-
agent(\`
|
|
203044
|
-
.then(v =>
|
|
203036
|
+
args.files,
|
|
203037
|
+
f => agent(\`Review \${f} for bugs.\`, { phase: 'Review', schema: findings }),
|
|
203038
|
+
(review, f) => parallel((review?.bugs ?? []).map(bug => () =>
|
|
203039
|
+
agent(\`Is this a real bug in \${f}? \${bug}\`, { phase: 'Verify', schema: verdict })
|
|
203040
|
+
.then(v => v?.real ? { file: f, bug } : null))),
|
|
203045
203041
|
)
|
|
203046
|
-
return
|
|
203047
|
-
|
|
203048
|
-
Script hooks: agent(prompt, opts?) spawns one subagent and resolves to final text. Prefer opts.schema (JSON Schema) for a validated object; invalid/missing results retry and then resolve to null with the validation error in the journal. opts.json still parses without validating; schema wins if both are supplied. Options: label, phase, schema, json, model, effort, allowedTools, systemPrompt, timeoutMs, maxToolCalls. pipeline(items, ...stages) runs each item through all stages independently with NO barrier between stages; each stage receives (prevResult, originalItem, index); a throwing stage drops that item to null. parallel(thunks) runs zero-arg functions concurrently and IS a barrier — use only when a stage genuinely needs all prior results together. phase(title) groups subsequent agents in progress output (inside concurrent stages use opts.phase instead — the global phase races). log(message) emits a progress line. args is the invocation's args input, verbatim.
|
|
203049
|
-
|
|
203050
|
-
Subagents run in isolated agent-free ephemeral conversations with read-only tools by default (Read, Grep, Glob) and no access to your memory or conversation — put ALL context they need in the prompt. Their model defaults to the invoking conversation's model; opts.model or the tool's model input accept any handle or alias from \`letta model list\`. They are told their final text IS the return value, so they return raw data. Concurrency is capped (excess agent() calls queue); a lifetime cap of 1000 agents per run is the runaway-loop backstop. Each subagent is also guarded: a 10-minute default timeout (override with opts.timeoutMs), at most 1000 unique tool calls by default (override with the positive safe integer opts.maxToolCalls), and a stop after three identical consecutive tool calls — a guarded call resolves to null and the journal records which guard fired.
|
|
203042
|
+
return results.filter(Boolean).flat().filter(Boolean)
|
|
203051
203043
|
|
|
203052
|
-
|
|
203053
|
-
|
|
203054
|
-
Before authoring a script, load the \`workflow-authoring\` skill — the workflow authoring reference: script API and gotchas, pipeline-vs-barrier rules, quality patterns (adversarial verify, judge panel, loop-until-dry), and worked examples.
|
|
203044
|
+
Before authoring a script, load the \`workflow-authoring\` skill — the script API, pipeline-vs-barrier rules, quality patterns, worked examples, and how to diagnose a run.
|
|
203055
203045
|
`;
|
|
203056
203046
|
var init_Workflow = () => {};
|
|
203057
203047
|
|
|
@@ -213029,7 +213019,7 @@ class CodexAppServerClient {
|
|
|
213029
213019
|
await this.request("initialize", {
|
|
213030
213020
|
clientInfo: {
|
|
213031
213021
|
name: "letta-code",
|
|
213032
|
-
version: "0.33.
|
|
213022
|
+
version: "0.33.5"
|
|
213033
213023
|
},
|
|
213034
213024
|
capabilities: null
|
|
213035
213025
|
});
|
|
@@ -220357,6 +220347,7 @@ function registerWorkflowExecution(params) {
|
|
|
220357
220347
|
startedAt: params.startedAt ?? Date.now(),
|
|
220358
220348
|
phases: (params.meta.phases ?? []).map((p2) => p2.title),
|
|
220359
220349
|
agents: new Map,
|
|
220350
|
+
decisionTokens: 0,
|
|
220360
220351
|
logs: []
|
|
220361
220352
|
});
|
|
220362
220353
|
notify();
|
|
@@ -220375,6 +220366,9 @@ function recordWorkflowProgress(taskId, event) {
|
|
|
220375
220366
|
if (record4.logs.length > MAX_LOG_LINES)
|
|
220376
220367
|
record4.logs.shift();
|
|
220377
220368
|
break;
|
|
220369
|
+
case "decision_usage":
|
|
220370
|
+
record4.decisionTokens += event.totalTokens;
|
|
220371
|
+
break;
|
|
220378
220372
|
case "agent": {
|
|
220379
220373
|
const previous = record4.agents.get(event.callIndex);
|
|
220380
220374
|
const phase = event.phase ?? previous?.phase ?? null;
|
|
@@ -220446,7 +220440,7 @@ function snapshot(record4, now2) {
|
|
|
220446
220440
|
agentsDone: agents.filter((a2) => a2.status === "done").length,
|
|
220447
220441
|
agentsFailed: agents.filter((a2) => a2.status === "error").length,
|
|
220448
220442
|
agentsRunning: agents.filter((a2) => a2.status === "running").length,
|
|
220449
|
-
totalTokens: agents.reduce((sum2, a2) => sum2 + (a2.totalTokens ?? 0), 0),
|
|
220443
|
+
totalTokens: record4.decisionTokens + agents.reduce((sum2, a2) => sum2 + (a2.totalTokens ?? 0), 0),
|
|
220450
220444
|
phases: phaseOrder.map((title) => ({
|
|
220451
220445
|
title,
|
|
220452
220446
|
agents: byPhase.get(title) ?? []
|
|
@@ -220647,6 +220641,22 @@ import { existsSync as existsSync45, readFileSync as readFileSync35 } from "node
|
|
|
220647
220641
|
import { createRequire as createRequire6 } from "node:module";
|
|
220648
220642
|
import { dirname as dirname26, join as join64 } from "node:path";
|
|
220649
220643
|
import { fileURLToPath as fileURLToPath7, pathToFileURL as pathToFileURL3 } from "node:url";
|
|
220644
|
+
function supportsPublishedResume(version2) {
|
|
220645
|
+
if (!version2 || !MIN_RESUME_SDK_VERSION)
|
|
220646
|
+
return false;
|
|
220647
|
+
const match2 = /^(\d+)\.(\d+)\.(\d+)$/.exec(version2);
|
|
220648
|
+
const minimum3 = MIN_RESUME_SDK_VERSION.split(".").map(Number);
|
|
220649
|
+
if (!match2)
|
|
220650
|
+
return false;
|
|
220651
|
+
const parts = match2.slice(1).map(Number);
|
|
220652
|
+
for (let index = 0;index < parts.length; index++) {
|
|
220653
|
+
const part = parts[index];
|
|
220654
|
+
const required5 = minimum3[index];
|
|
220655
|
+
if (part !== required5)
|
|
220656
|
+
return (part ?? 0) > (required5 ?? 0);
|
|
220657
|
+
}
|
|
220658
|
+
return true;
|
|
220659
|
+
}
|
|
220650
220660
|
function preferRunningCliForSubagents() {
|
|
220651
220661
|
if (process.env.LETTA_CLI_PATH)
|
|
220652
220662
|
return;
|
|
@@ -220655,6 +220665,17 @@ function preferRunningCliForSubagents() {
|
|
|
220655
220665
|
process.env.LETTA_CLI_PATH = entry;
|
|
220656
220666
|
}
|
|
220657
220667
|
}
|
|
220668
|
+
function packageVersion(entry) {
|
|
220669
|
+
for (let dir = dirname26(entry);; dir = dirname26(dir)) {
|
|
220670
|
+
try {
|
|
220671
|
+
const manifest = JSON.parse(readFileSync35(join64(dir, "package.json"), "utf8"));
|
|
220672
|
+
if (manifest.name === SDK_PACKAGE)
|
|
220673
|
+
return manifest.version;
|
|
220674
|
+
} catch {}
|
|
220675
|
+
if (dir === dirname26(dir))
|
|
220676
|
+
return;
|
|
220677
|
+
}
|
|
220678
|
+
}
|
|
220658
220679
|
function packageEntry(packageDir) {
|
|
220659
220680
|
try {
|
|
220660
220681
|
const manifest = JSON.parse(readFileSync35(join64(packageDir, "package.json"), "utf8"));
|
|
@@ -220722,6 +220743,7 @@ async function loadAgentSdk() {
|
|
|
220722
220743
|
continue;
|
|
220723
220744
|
}
|
|
220724
220745
|
return {
|
|
220746
|
+
supportsAgentFreeResume: process.env.LETTA_WORKFLOW_AGENT_FREE_RESUME === "1" && Boolean(envPath) && specifier === specifiers[0] || specifier.startsWith("file:") && supportsPublishedResume(packageVersion(fileURLToPath7(specifier))),
|
|
220725
220747
|
createLocalClient: () => {
|
|
220726
220748
|
const client = new sdk.LettaAgentClient({
|
|
220727
220749
|
backend: "local",
|
|
@@ -220751,12 +220773,26 @@ async function loadAgentSdk() {
|
|
|
220751
220773
|
${attempts.map((a2) => ` tried ${a2}`).join(`
|
|
220752
220774
|
`)}`);
|
|
220753
220775
|
}
|
|
220754
|
-
var SDK_PACKAGE;
|
|
220776
|
+
var SDK_PACKAGE, MIN_RESUME_SDK_VERSION = "0.8.20";
|
|
220755
220777
|
var init_sdk_loader = __esm(() => {
|
|
220756
220778
|
SDK_PACKAGE = ["@letta-ai", "letta-agent-sdk"].join("/");
|
|
220757
220779
|
});
|
|
220758
220780
|
|
|
220759
220781
|
// src/tools/workflow/sdk-spawner.ts
|
|
220782
|
+
async function latestWorkerRun(conversationId) {
|
|
220783
|
+
const client = await getClient();
|
|
220784
|
+
const messages = await client.conversations.messages.list(conversationId, {
|
|
220785
|
+
limit: 100,
|
|
220786
|
+
order: "desc"
|
|
220787
|
+
});
|
|
220788
|
+
const runId = messages.getPaginatedItems().map((message) => message.run_id).find((id2) => typeof id2 === "string" && id2.startsWith("run-"));
|
|
220789
|
+
if (!runId)
|
|
220790
|
+
return null;
|
|
220791
|
+
return client.runs.retrieve(runId);
|
|
220792
|
+
}
|
|
220793
|
+
async function retrieveWorkerConversation(id2) {
|
|
220794
|
+
return apiRequest("GET", `/v1/conversations/${encodeURIComponent(id2)}`);
|
|
220795
|
+
}
|
|
220760
220796
|
function parseJsonReply(text2) {
|
|
220761
220797
|
const trimmed = text2.trim();
|
|
220762
220798
|
const fenced = /^```(?:json)?\s*([\s\S]*?)\s*```$/.exec(trimmed);
|
|
@@ -220842,14 +220878,20 @@ function usageTokensFromEvent(event) {
|
|
|
220842
220878
|
const total = event.total_tokens;
|
|
220843
220879
|
return typeof total === "number" && Number.isFinite(total) ? total : undefined;
|
|
220844
220880
|
}
|
|
220845
|
-
async function drainTurn(query3, usage, stop, maxToolCalls, onUsage) {
|
|
220881
|
+
async function drainTurn(query3, usage, stop, maxToolCalls, onUsage, onStarted) {
|
|
220846
220882
|
let assistantText2 = "";
|
|
220847
220883
|
let resultText;
|
|
220848
220884
|
let success = false;
|
|
220849
220885
|
let error4;
|
|
220850
220886
|
let structuredOutput;
|
|
220887
|
+
let startedNotified = false;
|
|
220851
220888
|
const guard = createToolCallGuard(maxToolCalls);
|
|
220852
220889
|
for await (const message of query3) {
|
|
220890
|
+
const id2 = query3.conversationId ?? message.conversationId;
|
|
220891
|
+
if (!startedNotified && id2) {
|
|
220892
|
+
startedNotified = true;
|
|
220893
|
+
onStarted?.(id2);
|
|
220894
|
+
}
|
|
220853
220895
|
if (message.type === "assistant")
|
|
220854
220896
|
assistantText2 += message.content ?? "";
|
|
220855
220897
|
if (message.type === "stream_event") {
|
|
@@ -220900,16 +220942,44 @@ function buildQueryOptions(options, model, config, callIndex) {
|
|
|
220900
220942
|
name: options.label ?? `Workflow worker ${callIndex + 1}`,
|
|
220901
220943
|
system: system2,
|
|
220902
220944
|
permissionMode: "unrestricted",
|
|
220903
|
-
allowedTools: options.allowedTools ?? config.allowedTools ?? DEFAULT_ALLOWED_TOOLS,
|
|
220945
|
+
allowedTools: options.allowedTools ?? (options.conversationId ? [] : config.allowedTools ?? DEFAULT_ALLOWED_TOOLS),
|
|
220904
220946
|
skillSources: [],
|
|
220905
220947
|
...config.cwd ? { cwd: config.cwd } : {},
|
|
220948
|
+
disableMemoryGuard: true,
|
|
220906
220949
|
...options.effort ? { modelSettings: { reasoning_effort: options.effort } } : {}
|
|
220907
220950
|
};
|
|
220908
220951
|
}
|
|
220909
220952
|
function createSdkSpawner(client, config) {
|
|
220910
220953
|
return async (request, signal, hooks) => {
|
|
220911
220954
|
const { prompt, options } = request;
|
|
220912
|
-
const
|
|
220955
|
+
const resumeId = options.conversationId;
|
|
220956
|
+
if (resumeId !== undefined && !/^conv-[A-Za-z0-9_-]+$/.test(resumeId)) {
|
|
220957
|
+
throw new Error("agent() conversationId must be a conv-... ID.");
|
|
220958
|
+
}
|
|
220959
|
+
if (resumeId && !config.supportsAgentFreeResume) {
|
|
220960
|
+
throw new Error("Workflow worker continuation requires an Agent SDK release with agent-free query() resume support.");
|
|
220961
|
+
}
|
|
220962
|
+
const persisted = resumeId ? await (config.retrieveConversation ?? retrieveWorkerConversation)(resumeId) : null;
|
|
220963
|
+
if (persisted && (persisted.agent_id !== null || persisted.parent_agent_id !== config.parentAgentId)) {
|
|
220964
|
+
throw new Error("Worker conversation is not agent-free or belongs to another parent agent.");
|
|
220965
|
+
}
|
|
220966
|
+
if (persisted && resumeId) {
|
|
220967
|
+
const latest = await (config.latestRun ?? latestWorkerRun)(resumeId);
|
|
220968
|
+
if (!latest || latest.conversation_id !== resumeId || !["completed", "failed", "cancelled"].includes(latest.status ?? "")) {
|
|
220969
|
+
throw new Error("Cannot confirm worker's latest run is terminal; reconcile it before continuing.");
|
|
220970
|
+
}
|
|
220971
|
+
}
|
|
220972
|
+
if (persisted && (!persisted.model || typeof persisted.model !== "string")) {
|
|
220973
|
+
throw new Error("Worker conversation has no persisted model; cannot continue safely.");
|
|
220974
|
+
}
|
|
220975
|
+
const selectedModel = options.model ? config.resolveModel?.(options.model) ?? null : config.model;
|
|
220976
|
+
if (persisted && options.systemPrompt !== undefined) {
|
|
220977
|
+
throw new Error("agent() continuation cannot override the worker system prompt.");
|
|
220978
|
+
}
|
|
220979
|
+
if (persisted && options.model && selectedModel !== persisted.model) {
|
|
220980
|
+
throw new Error("agent() continuation model must match the persisted worker model.");
|
|
220981
|
+
}
|
|
220982
|
+
const model = persisted ? persisted.model : selectedModel;
|
|
220913
220983
|
if (!model) {
|
|
220914
220984
|
return {
|
|
220915
220985
|
value: null,
|
|
@@ -220928,8 +220998,15 @@ function createSdkSpawner(client, config) {
|
|
|
220928
220998
|
const usage = {};
|
|
220929
220999
|
const query3 = client.query({
|
|
220930
221000
|
prompt,
|
|
220931
|
-
options:
|
|
221001
|
+
options: {
|
|
221002
|
+
...buildQueryOptions(options, model, config, request.callIndex),
|
|
221003
|
+
...resumeId ? { conversationId: resumeId } : {}
|
|
221004
|
+
}
|
|
220932
221005
|
});
|
|
221006
|
+
if (resumeId && query3.conversationId && query3.conversationId !== resumeId) {
|
|
221007
|
+
query3.close();
|
|
221008
|
+
throw new Error("SDK resumed an unexpected worker conversation; refusing continuation.");
|
|
221009
|
+
}
|
|
220933
221010
|
let settleStopped;
|
|
220934
221011
|
const stopped = new Promise((resolve30) => {
|
|
220935
221012
|
settleStopped = resolve30;
|
|
@@ -220959,44 +221036,68 @@ function createSdkSpawner(client, config) {
|
|
|
220959
221036
|
drainTurn(query3, usage, stop, options.maxToolCalls ?? DEFAULT_MAX_SUBAGENT_TOOL_CALLS, (totalTokens) => {
|
|
220960
221037
|
if (!finished2)
|
|
220961
221038
|
hooks?.onUsage?.(totalTokens);
|
|
221039
|
+
}, (id2) => {
|
|
221040
|
+
if (resumeId && id2 !== resumeId) {
|
|
221041
|
+
stop("SDK resumed an unexpected worker conversation");
|
|
221042
|
+
} else if (!finished2) {
|
|
221043
|
+
hooks?.onStarted?.(id2);
|
|
221044
|
+
}
|
|
220962
221045
|
}),
|
|
220963
221046
|
stopped
|
|
220964
221047
|
]);
|
|
221048
|
+
if (resumeId && query3.conversationId !== resumeId) {
|
|
221049
|
+
throw new Error("SDK did not resume the requested worker conversation.");
|
|
221050
|
+
}
|
|
220965
221051
|
const stats = {
|
|
220966
221052
|
durationMs: Date.now() - startedAt,
|
|
220967
221053
|
...turn.totalTokens !== undefined ? { totalTokens: turn.totalTokens } : {},
|
|
220968
221054
|
...query3.conversationId ? { conversationId: query3.conversationId } : {}
|
|
220969
221055
|
};
|
|
220970
221056
|
if (!turn.success) {
|
|
220971
|
-
|
|
221057
|
+
const outcome2 = {
|
|
220972
221058
|
value: null,
|
|
220973
221059
|
failed: true,
|
|
220974
221060
|
error: turn.error ?? "subagent turn failed",
|
|
220975
221061
|
...stats
|
|
220976
221062
|
};
|
|
221063
|
+
return outcome2;
|
|
220977
221064
|
}
|
|
220978
221065
|
if (options.schema) {
|
|
220979
|
-
|
|
221066
|
+
const outcome2 = {
|
|
221067
|
+
value: turn.structuredOutput,
|
|
221068
|
+
failed: false,
|
|
221069
|
+
...stats
|
|
221070
|
+
};
|
|
221071
|
+
return outcome2;
|
|
220980
221072
|
}
|
|
220981
221073
|
if (options.json) {
|
|
220982
221074
|
try {
|
|
220983
|
-
|
|
221075
|
+
const outcome2 = {
|
|
220984
221076
|
value: parseJsonReply(turn.finalText),
|
|
220985
221077
|
failed: false,
|
|
220986
221078
|
...stats
|
|
220987
221079
|
};
|
|
221080
|
+
return outcome2;
|
|
220988
221081
|
} catch {
|
|
220989
|
-
|
|
221082
|
+
const outcome2 = {
|
|
220990
221083
|
value: null,
|
|
220991
221084
|
failed: true,
|
|
220992
221085
|
error: `Subagent reply was not valid JSON: ${turn.finalText.slice(0, 200)}`,
|
|
220993
221086
|
...stats
|
|
220994
221087
|
};
|
|
221088
|
+
return outcome2;
|
|
220995
221089
|
}
|
|
220996
221090
|
}
|
|
220997
|
-
|
|
221091
|
+
const outcome = { value: turn.finalText, failed: false, ...stats };
|
|
221092
|
+
return outcome;
|
|
220998
221093
|
} catch (error4) {
|
|
220999
|
-
|
|
221094
|
+
const outcome = {
|
|
221095
|
+
value: null,
|
|
221096
|
+
failed: true,
|
|
221097
|
+
error: String(error4),
|
|
221098
|
+
...query3.conversationId || resumeId ? { conversationId: query3.conversationId ?? resumeId } : {}
|
|
221099
|
+
};
|
|
221100
|
+
return outcome;
|
|
221000
221101
|
} finally {
|
|
221001
221102
|
finished2 = true;
|
|
221002
221103
|
clearTimeout(timeout);
|
|
@@ -221007,10 +221108,140 @@ function createSdkSpawner(client, config) {
|
|
|
221007
221108
|
}
|
|
221008
221109
|
var DEFAULT_ALLOWED_TOOLS, DEFAULT_SUBAGENT_TIMEOUT_MS, DEFAULT_MAX_SUBAGENT_TOOL_CALLS = 1000, MAX_IDENTICAL_TOOL_CALLS = 3, SUBAGENT_PREAMBLE = `You are a subagent inside a deterministic workflow. You are not talking to a human: your final output is consumed by a script. Return raw data with no preamble, no markdown framing, and no questions.`, JSON_PREAMBLE = `Your final message must be a single JSON value and nothing else: no prose, no markdown code fence.`;
|
|
221009
221110
|
var init_sdk_spawner = __esm(() => {
|
|
221111
|
+
init_client4();
|
|
221112
|
+
init_request();
|
|
221010
221113
|
DEFAULT_ALLOWED_TOOLS = ["Read", "Grep", "Glob"];
|
|
221011
221114
|
DEFAULT_SUBAGENT_TIMEOUT_MS = 10 * 60 * 1000;
|
|
221012
221115
|
});
|
|
221013
221116
|
|
|
221117
|
+
// src/tools/workflow/decide.ts
|
|
221118
|
+
function isRecord9(value) {
|
|
221119
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
221120
|
+
}
|
|
221121
|
+
function isFiniteNumber2(value) {
|
|
221122
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
221123
|
+
}
|
|
221124
|
+
function validateRequest(input) {
|
|
221125
|
+
if (!isRecord9(input))
|
|
221126
|
+
throw new Error("decide() requires a request object.");
|
|
221127
|
+
const { state, questions, provider, session_id, trace, user } = input;
|
|
221128
|
+
if (Object.hasOwn(input, "model"))
|
|
221129
|
+
throw new Error("decide() does not accept a model option.");
|
|
221130
|
+
if (!(typeof state === "string" || isRecord9(state) || Array.isArray(state))) {
|
|
221131
|
+
throw new Error("decide() state must be a string, object, or array.");
|
|
221132
|
+
}
|
|
221133
|
+
if (!isRecord9(questions) || Object.keys(questions).length === 0) {
|
|
221134
|
+
throw new Error("decide() questions must be a non-empty object.");
|
|
221135
|
+
}
|
|
221136
|
+
for (const [id2, question] of Object.entries(questions)) {
|
|
221137
|
+
if (!isRecord9(question) || typeof question.instructions !== "string" || !question.instructions.trim()) {
|
|
221138
|
+
throw new Error(`decide() question ${id2} requires instructions.`);
|
|
221139
|
+
}
|
|
221140
|
+
if (question.type === "choice") {
|
|
221141
|
+
if (!isRecord9(question.criteria) || Object.keys(question.criteria).length === 0 || Object.keys(question.criteria).length > 255 || !Object.values(question.criteria).every((value) => typeof value === "string")) {
|
|
221142
|
+
throw new Error(`decide() choice ${id2} requires a non-empty criteria map (at most 255 options).`);
|
|
221143
|
+
}
|
|
221144
|
+
} else if (question.type === "score") {
|
|
221145
|
+
if (!Array.isArray(question.criteria) || question.criteria.length === 0 || !question.criteria.every((value) => typeof value === "string")) {
|
|
221146
|
+
throw new Error(`decide() score ${id2} requires a non-empty criteria array.`);
|
|
221147
|
+
}
|
|
221148
|
+
} else if (question.type !== "noul") {
|
|
221149
|
+
throw new Error(`decide() question ${id2} has an unsupported type.`);
|
|
221150
|
+
}
|
|
221151
|
+
}
|
|
221152
|
+
if (provider !== undefined && !isRecord9(provider))
|
|
221153
|
+
throw new Error("decide() provider must be an object.");
|
|
221154
|
+
if (isRecord9(provider) && provider.allow_fallbacks === true) {
|
|
221155
|
+
throw new Error("decide() does not allow model/provider fallbacks.");
|
|
221156
|
+
}
|
|
221157
|
+
if (session_id !== undefined && (typeof session_id !== "string" || session_id.length > 256)) {
|
|
221158
|
+
throw new Error("decide() session_id must be a string of at most 256 characters.");
|
|
221159
|
+
}
|
|
221160
|
+
if (trace !== undefined && !isRecord9(trace))
|
|
221161
|
+
throw new Error("decide() trace must be an object.");
|
|
221162
|
+
if (user !== undefined && typeof user !== "string")
|
|
221163
|
+
throw new Error("decide() user must be a string.");
|
|
221164
|
+
return input;
|
|
221165
|
+
}
|
|
221166
|
+
function validProbabilityMap(value) {
|
|
221167
|
+
return isRecord9(value) && Object.values(value).every(isFiniteNumber2);
|
|
221168
|
+
}
|
|
221169
|
+
function validAnswer(answer, question) {
|
|
221170
|
+
if (!isRecord9(answer) || answer.type !== question.type)
|
|
221171
|
+
return false;
|
|
221172
|
+
if (answer.type === "choice") {
|
|
221173
|
+
return typeof answer.choice === "string" && isRecord9(question.criteria) && Object.hasOwn(question.criteria, answer.choice) && (answer.probabilities === undefined || validProbabilityMap(answer.probabilities)) && (answer.confidence === undefined || isFiniteNumber2(answer.confidence));
|
|
221174
|
+
}
|
|
221175
|
+
if (answer.type === "score") {
|
|
221176
|
+
return isFiniteNumber2(answer.score) && isRecord9(answer.legend) && Object.values(answer.legend).every((value) => typeof value === "string") && (answer.probabilities === undefined || validProbabilityMap(answer.probabilities)) && (answer.confidence === undefined || isFiniteNumber2(answer.confidence));
|
|
221177
|
+
}
|
|
221178
|
+
return answer.type === "noul" && isFiniteNumber2(answer.noul) && answer.noul >= 0 && answer.noul <= 1;
|
|
221179
|
+
}
|
|
221180
|
+
function validateResponse(response, request) {
|
|
221181
|
+
if (!isRecord9(response) || typeof response.model !== "string" || typeof response.id !== "string" || typeof response.provider !== "string" || !isRecord9(response.usage) || !isFiniteNumber2(response.usage.input_tokens) || !isFiniteNumber2(response.usage.output_tokens) || !isFiniteNumber2(response.usage.cost) || !isRecord9(response.answers)) {
|
|
221182
|
+
throw new Error("decide() received a malformed response.");
|
|
221183
|
+
}
|
|
221184
|
+
const answers = response.answers;
|
|
221185
|
+
const questionIds = Object.keys(request.questions);
|
|
221186
|
+
if (Object.keys(answers).length !== questionIds.length || questionIds.some((id2) => !validAnswer(answers[id2], request.questions[id2]))) {
|
|
221187
|
+
throw new InvalidDecisionAnswerError;
|
|
221188
|
+
}
|
|
221189
|
+
return {
|
|
221190
|
+
...response,
|
|
221191
|
+
answers: Object.fromEntries(questionIds.map((id2) => [
|
|
221192
|
+
id2,
|
|
221193
|
+
{ ...answers[id2], calibrated: true }
|
|
221194
|
+
]))
|
|
221195
|
+
};
|
|
221196
|
+
}
|
|
221197
|
+
async function submitWorkflowDecision(input, signal, onResult) {
|
|
221198
|
+
const request = validateRequest(input);
|
|
221199
|
+
const body3 = {
|
|
221200
|
+
...request,
|
|
221201
|
+
model: DEFAULT_JEV_MODEL,
|
|
221202
|
+
provider: { ...request.provider, allow_fallbacks: false }
|
|
221203
|
+
};
|
|
221204
|
+
for (let attempt2 = 0;attempt2 < 2; attempt2++) {
|
|
221205
|
+
if (signal.aborted)
|
|
221206
|
+
throw new Error("Workflow aborted.");
|
|
221207
|
+
const response = await apiRequest("POST", "/v1/alpha/decisions", body3, { signal: AbortSignal.any([signal, AbortSignal.timeout(35000)]) });
|
|
221208
|
+
try {
|
|
221209
|
+
const result3 = validateResponse(response, request);
|
|
221210
|
+
onResult?.({
|
|
221211
|
+
model: result3.model,
|
|
221212
|
+
cost: result3.usage.cost,
|
|
221213
|
+
calibrated: true,
|
|
221214
|
+
valid: true,
|
|
221215
|
+
totalTokens: result3.usage.input_tokens + result3.usage.output_tokens
|
|
221216
|
+
});
|
|
221217
|
+
return result3;
|
|
221218
|
+
} catch (error4) {
|
|
221219
|
+
if (!(error4 instanceof InvalidDecisionAnswerError))
|
|
221220
|
+
throw error4;
|
|
221221
|
+
const usage = response.usage;
|
|
221222
|
+
onResult?.({
|
|
221223
|
+
model: response.model,
|
|
221224
|
+
cost: usage.cost,
|
|
221225
|
+
calibrated: false,
|
|
221226
|
+
valid: false,
|
|
221227
|
+
totalTokens: usage.input_tokens + usage.output_tokens
|
|
221228
|
+
});
|
|
221229
|
+
if (attempt2 === 1)
|
|
221230
|
+
return null;
|
|
221231
|
+
}
|
|
221232
|
+
}
|
|
221233
|
+
return null;
|
|
221234
|
+
}
|
|
221235
|
+
var DEFAULT_JEV_MODEL = "~typesafe/jev-latest", InvalidDecisionAnswerError;
|
|
221236
|
+
var init_decide = __esm(() => {
|
|
221237
|
+
init_request();
|
|
221238
|
+
InvalidDecisionAnswerError = class InvalidDecisionAnswerError extends Error {
|
|
221239
|
+
constructor() {
|
|
221240
|
+
super("decide() received invalid answers for the requested questions.");
|
|
221241
|
+
}
|
|
221242
|
+
};
|
|
221243
|
+
});
|
|
221244
|
+
|
|
221014
221245
|
// src/tools/workflow/workflow-engine.ts
|
|
221015
221246
|
import vm2 from "node:vm";
|
|
221016
221247
|
|
|
@@ -221049,18 +221280,57 @@ async function executeWorkflow(spawner, options) {
|
|
|
221049
221280
|
};
|
|
221050
221281
|
const inFlight = new Set;
|
|
221051
221282
|
const maxTotalAgents = options.maxTotalAgents ?? DEFAULT_MAX_TOTAL_AGENTS;
|
|
221283
|
+
const maxTotalDecisions = options.maxTotalDecisions ?? DEFAULT_MAX_TOTAL_DECISIONS;
|
|
221052
221284
|
const semaphore = new Semaphore(options.maxConcurrent ?? DEFAULT_MAX_CONCURRENT);
|
|
221053
221285
|
let currentPhase = null;
|
|
221054
221286
|
let callCounter = 0;
|
|
221287
|
+
let decisionCounter = 0;
|
|
221055
221288
|
let agentsSpawned = 0;
|
|
221056
221289
|
let totalTokens = 0;
|
|
221057
|
-
function
|
|
221058
|
-
const pending2 = callAgent(prompt, callOptions);
|
|
221290
|
+
function trackCall(pending2) {
|
|
221059
221291
|
pending2.catch(() => {});
|
|
221060
221292
|
inFlight.add(pending2);
|
|
221061
221293
|
pending2.finally(() => inFlight.delete(pending2)).catch(() => {});
|
|
221062
221294
|
return pending2;
|
|
221063
221295
|
}
|
|
221296
|
+
function agent(prompt, callOptions) {
|
|
221297
|
+
return trackCall(callAgent(prompt, callOptions));
|
|
221298
|
+
}
|
|
221299
|
+
function decide(state, questions, callOptions) {
|
|
221300
|
+
return trackCall(callDecision(state, questions, callOptions));
|
|
221301
|
+
}
|
|
221302
|
+
async function callDecision(state, questions, callOptions) {
|
|
221303
|
+
if (signal.aborted)
|
|
221304
|
+
throw new Error("Workflow aborted.");
|
|
221305
|
+
if (decisionCounter >= maxTotalDecisions) {
|
|
221306
|
+
throw new Error(`Lifetime decision cap of ${maxTotalDecisions} reached.`);
|
|
221307
|
+
}
|
|
221308
|
+
if (callOptions !== undefined && (!callOptions || typeof callOptions !== "object" || Array.isArray(callOptions))) {
|
|
221309
|
+
throw new Error("decide() options must be an object.");
|
|
221310
|
+
}
|
|
221311
|
+
decisionCounter++;
|
|
221312
|
+
await semaphore.acquire();
|
|
221313
|
+
try {
|
|
221314
|
+
if (signal.aborted)
|
|
221315
|
+
throw new Error("Workflow aborted.");
|
|
221316
|
+
return await submitWorkflowDecision({
|
|
221317
|
+
...callOptions,
|
|
221318
|
+
state,
|
|
221319
|
+
questions
|
|
221320
|
+
}, signal, (result3) => {
|
|
221321
|
+
totalTokens += result3.totalTokens;
|
|
221322
|
+
emit({ kind: "decision_usage", totalTokens: result3.totalTokens });
|
|
221323
|
+
if (options.journalPath) {
|
|
221324
|
+
appendJournalEntry(options.journalPath, {
|
|
221325
|
+
kind: "decision",
|
|
221326
|
+
...result3
|
|
221327
|
+
});
|
|
221328
|
+
}
|
|
221329
|
+
});
|
|
221330
|
+
} finally {
|
|
221331
|
+
semaphore.release();
|
|
221332
|
+
}
|
|
221333
|
+
}
|
|
221064
221334
|
async function callAgent(prompt, callOptions) {
|
|
221065
221335
|
if (typeof prompt !== "string" || !prompt.trim()) {
|
|
221066
221336
|
throw new Error("agent() requires a non-empty prompt string.");
|
|
@@ -221074,6 +221344,9 @@ async function executeWorkflow(spawner, options) {
|
|
|
221074
221344
|
throw new Error("agent() options must be an object.");
|
|
221075
221345
|
}
|
|
221076
221346
|
const opts = { ...callOptions };
|
|
221347
|
+
if (opts.conversationId !== undefined && (typeof opts.conversationId !== "string" || !/^conv-[A-Za-z0-9_-]+$/.test(opts.conversationId))) {
|
|
221348
|
+
throw new Error("agent() conversationId must be a conv-... ID.");
|
|
221349
|
+
}
|
|
221077
221350
|
if (opts.maxToolCalls !== undefined && (!Number.isSafeInteger(opts.maxToolCalls) || opts.maxToolCalls <= 0)) {
|
|
221078
221351
|
throw new Error("agent() maxToolCalls must be a positive safe integer.");
|
|
221079
221352
|
}
|
|
@@ -221088,6 +221361,15 @@ async function executeWorkflow(spawner, options) {
|
|
|
221088
221361
|
emit({ kind: "agent", callIndex, label, phase: phase2, status: "running" });
|
|
221089
221362
|
agentsSpawned++;
|
|
221090
221363
|
const outcome = await spawner({ prompt, options: opts, callIndex }, signal, {
|
|
221364
|
+
onStarted: (conversationId) => {
|
|
221365
|
+
if (options.journalPath) {
|
|
221366
|
+
appendJournalEntry(options.journalPath, {
|
|
221367
|
+
kind: "agent_started",
|
|
221368
|
+
callIndex,
|
|
221369
|
+
conversationId
|
|
221370
|
+
});
|
|
221371
|
+
}
|
|
221372
|
+
},
|
|
221091
221373
|
onUsage: (totalTokens2) => emit({
|
|
221092
221374
|
kind: "agent",
|
|
221093
221375
|
callIndex,
|
|
@@ -221103,6 +221385,7 @@ async function executeWorkflow(spawner, options) {
|
|
|
221103
221385
|
callIndex,
|
|
221104
221386
|
label,
|
|
221105
221387
|
prompt,
|
|
221388
|
+
...opts.conversationId ? { resumedConversationId: opts.conversationId } : {},
|
|
221106
221389
|
outcome
|
|
221107
221390
|
});
|
|
221108
221391
|
}
|
|
@@ -221172,6 +221455,7 @@ async function executeWorkflow(spawner, options) {
|
|
|
221172
221455
|
}
|
|
221173
221456
|
const context3 = vm2.createContext({
|
|
221174
221457
|
agent,
|
|
221458
|
+
decide,
|
|
221175
221459
|
parallel,
|
|
221176
221460
|
pipeline: pipeline6,
|
|
221177
221461
|
phase,
|
|
@@ -221219,8 +221503,9 @@ ${stripMetaExport(options.script)}
|
|
|
221219
221503
|
settled = true;
|
|
221220
221504
|
}
|
|
221221
221505
|
}
|
|
221222
|
-
var DEFAULT_MAX_CONCURRENT = 16, DEFAULT_MAX_TOTAL_AGENTS = 1000, MAX_ITEMS_PER_HELPER = 4096;
|
|
221506
|
+
var DEFAULT_MAX_CONCURRENT = 16, DEFAULT_MAX_TOTAL_AGENTS = 1000, DEFAULT_MAX_TOTAL_DECISIONS = 1000, MAX_ITEMS_PER_HELPER = 4096;
|
|
221223
221507
|
var init_workflow_engine = __esm(() => {
|
|
221508
|
+
init_decide();
|
|
221224
221509
|
init_journal();
|
|
221225
221510
|
init_meta3();
|
|
221226
221511
|
});
|
|
@@ -221274,7 +221559,8 @@ async function createSdkSpawnerHandle(args, setStage = () => {}) {
|
|
|
221274
221559
|
model,
|
|
221275
221560
|
resolveModel,
|
|
221276
221561
|
allowedTools: args.allowedTools ?? [...DEFAULT_ALLOWED_TOOLS],
|
|
221277
|
-
cwd: getCurrentWorkingDirectory()
|
|
221562
|
+
cwd: getCurrentWorkingDirectory(),
|
|
221563
|
+
supportsAgentFreeResume: sdk.supportsAgentFreeResume
|
|
221278
221564
|
});
|
|
221279
221565
|
} catch (error4) {
|
|
221280
221566
|
client[Symbol.asyncDispose]?.().catch(() => {
|
|
@@ -221297,6 +221583,8 @@ function formatWorkflowProgressLine(event) {
|
|
|
221297
221583
|
return `── ${event.title} ──`;
|
|
221298
221584
|
case "log":
|
|
221299
221585
|
return `» ${event.message}`;
|
|
221586
|
+
case "decision_usage":
|
|
221587
|
+
return null;
|
|
221300
221588
|
case "agent": {
|
|
221301
221589
|
if (event.status === "queued")
|
|
221302
221590
|
return null;
|
|
@@ -221342,7 +221630,7 @@ function formatCompletionResult(run, executionDir) {
|
|
|
221342
221630
|
return [
|
|
221343
221631
|
payload,
|
|
221344
221632
|
"",
|
|
221345
|
-
`Per-
|
|
221633
|
+
`Per-call results: ${join65(executionDir, "journal.jsonl")} — one line per completed agent call with its full return value, plus one per decide() API attempt (retries included) with its model, cost, calibration, and tokens.`,
|
|
221346
221634
|
"If the result above is empty or unexpected, read that file BEFORE diagnosing — do not assume agents returned non-empty results."
|
|
221347
221635
|
].join(`
|
|
221348
221636
|
`);
|
|
@@ -221561,7 +221849,7 @@ ${result3}
|
|
|
221561
221849
|
`Workflow launched in background. Task ID: ${taskId}`,
|
|
221562
221850
|
`Summary: ${meta.description}`,
|
|
221563
221851
|
`Script file: ${scriptPath}`,
|
|
221564
|
-
`Journal: ${journalPath} (one line per completed agent)`,
|
|
221852
|
+
`Journal: ${journalPath} (one line per completed agent, and per decide() API attempt including retries)`,
|
|
221565
221853
|
`Output file: ${outputFile}`,
|
|
221566
221854
|
"",
|
|
221567
221855
|
"You will be notified when it completes. Do not poll or sleep — keep working or end your turn. Read the output file only when you need interim progress; TaskStop aborts the run; the user can watch live status with /workflows."
|
|
@@ -398828,7 +399116,7 @@ function createModChangeBatcher(onChange) {
|
|
|
398828
399116
|
// src/mods/package-manifest.ts
|
|
398829
399117
|
import { readFileSync as readFileSync37 } from "node:fs";
|
|
398830
399118
|
import path35 from "node:path";
|
|
398831
|
-
function
|
|
399119
|
+
function isRecord10(value) {
|
|
398832
399120
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
398833
399121
|
}
|
|
398834
399122
|
function addError(errors4, errorPath, message) {
|
|
@@ -398967,7 +399255,7 @@ function validateCapabilities(value, errors4) {
|
|
|
398967
399255
|
function validateEngines(value, errors4) {
|
|
398968
399256
|
if (value === undefined)
|
|
398969
399257
|
return;
|
|
398970
|
-
if (!
|
|
399258
|
+
if (!isRecord10(value)) {
|
|
398971
399259
|
addError(errors4, "letta.engines", "engines must be an object");
|
|
398972
399260
|
return;
|
|
398973
399261
|
}
|
|
@@ -398992,7 +399280,7 @@ function validateEngines(value, errors4) {
|
|
|
398992
399280
|
return Object.keys(engines).length > 0 ? engines : undefined;
|
|
398993
399281
|
}
|
|
398994
399282
|
function parseLettaPackageManifest(packageJson) {
|
|
398995
|
-
if (!
|
|
399283
|
+
if (!isRecord10(packageJson)) {
|
|
398996
399284
|
return {
|
|
398997
399285
|
errors: [{ message: "package.json must be an object", path: "package" }],
|
|
398998
399286
|
manifest: null,
|
|
@@ -399003,7 +399291,7 @@ function parseLettaPackageManifest(packageJson) {
|
|
|
399003
399291
|
if (rawManifest === undefined) {
|
|
399004
399292
|
return { errors: [], manifest: null, ok: true };
|
|
399005
399293
|
}
|
|
399006
|
-
if (!
|
|
399294
|
+
if (!isRecord10(rawManifest)) {
|
|
399007
399295
|
return {
|
|
399008
399296
|
errors: [{ message: "letta manifest must be an object", path: "letta" }],
|
|
399009
399297
|
manifest: null,
|
|
@@ -399073,7 +399361,7 @@ import {
|
|
|
399073
399361
|
writeFileSync as writeFileSync28
|
|
399074
399362
|
} from "node:fs";
|
|
399075
399363
|
import path36 from "node:path";
|
|
399076
|
-
function
|
|
399364
|
+
function isRecord11(value) {
|
|
399077
399365
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
399078
399366
|
}
|
|
399079
399367
|
function createDiagnostic(diagnosticPath, message) {
|
|
@@ -399150,7 +399438,7 @@ function readRegistryObject(modsRoot) {
|
|
|
399150
399438
|
registryPath
|
|
399151
399439
|
};
|
|
399152
399440
|
}
|
|
399153
|
-
if (!
|
|
399441
|
+
if (!isRecord11(registryResult.value)) {
|
|
399154
399442
|
return {
|
|
399155
399443
|
diagnostics: [
|
|
399156
399444
|
createDiagnostic(registryPath, "packages.json must be an object")
|
|
@@ -399227,7 +399515,7 @@ function resolvePackageEntry(packageRoot, entry) {
|
|
|
399227
399515
|
}
|
|
399228
399516
|
function validatePackageMetadata(modsRoot, rawEntry, index) {
|
|
399229
399517
|
const diagnosticPath = `packages[${index}]`;
|
|
399230
|
-
if (!
|
|
399518
|
+
if (!isRecord11(rawEntry)) {
|
|
399231
399519
|
return {
|
|
399232
399520
|
diagnostics: [
|
|
399233
399521
|
createDiagnostic(diagnosticPath, "package registry entry must be an object")
|
|
@@ -399594,7 +399882,7 @@ function setManagedModPackageEnabled(params) {
|
|
|
399594
399882
|
const registry3 = readMutablePackageRegistry(params.modsRoot);
|
|
399595
399883
|
const match3 = findPackageIndex(params.modsRoot, registry3.packagesValue, params.specifier);
|
|
399596
399884
|
const rawEntry = registry3.packagesValue[match3.index];
|
|
399597
|
-
if (!
|
|
399885
|
+
if (!isRecord11(rawEntry)) {
|
|
399598
399886
|
throw new Error("Invalid package entry");
|
|
399599
399887
|
}
|
|
399600
399888
|
rawEntry.enabled = params.enabled;
|
|
@@ -399640,7 +399928,7 @@ function upsertManagedModPackage(params) {
|
|
|
399640
399928
|
let removedDuplicates = 0;
|
|
399641
399929
|
let replaced = false;
|
|
399642
399930
|
registry3.packagesValue.forEach((rawEntry) => {
|
|
399643
|
-
if (
|
|
399931
|
+
if (isRecord11(rawEntry) && rawEntry.source === params.source) {
|
|
399644
399932
|
if (!replaced) {
|
|
399645
399933
|
insertionIndex = nextPackages.length;
|
|
399646
399934
|
nextPackages.push(entry);
|
|
@@ -399804,7 +400092,7 @@ var init_runtime_dependencies = __esm(() => {
|
|
|
399804
400092
|
});
|
|
399805
400093
|
|
|
399806
400094
|
// src/mods/turn-start-cancel.ts
|
|
399807
|
-
function
|
|
400095
|
+
function isRecord12(value) {
|
|
399808
400096
|
return typeof value === "object" && value !== null;
|
|
399809
400097
|
}
|
|
399810
400098
|
function normalizeTurnStartCancelReason(value) {
|
|
@@ -399816,7 +400104,7 @@ function normalizeTurnStartCancelReason(value) {
|
|
|
399816
400104
|
return trimmed.length > MAX_TURN_START_CANCEL_REASON_LENGTH ? trimmed.slice(0, MAX_TURN_START_CANCEL_REASON_LENGTH) : trimmed;
|
|
399817
400105
|
}
|
|
399818
400106
|
function getTurnStartCancel(event) {
|
|
399819
|
-
if (!
|
|
400107
|
+
if (!isRecord12(event) || !isRecord12(event.cancel))
|
|
399820
400108
|
return null;
|
|
399821
400109
|
const reason = normalizeTurnStartCancelReason(event.cancel.reason);
|
|
399822
400110
|
return reason ? { reason } : null;
|
|
@@ -406461,14 +406749,14 @@ var init_approval_suggestions = __esm(async () => {
|
|
|
406461
406749
|
});
|
|
406462
406750
|
|
|
406463
406751
|
// src/websocket/listener/cloud-retry-message.ts
|
|
406464
|
-
function
|
|
406752
|
+
function isRecord13(value) {
|
|
406465
406753
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
406466
406754
|
}
|
|
406467
406755
|
function optionalString4(value) {
|
|
406468
406756
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
406469
406757
|
}
|
|
406470
406758
|
function parseCloudRetryMessage(value) {
|
|
406471
|
-
if (!
|
|
406759
|
+
if (!isRecord13(value) || value.message_type !== "retry_message") {
|
|
406472
406760
|
return null;
|
|
406473
406761
|
}
|
|
406474
406762
|
const attempt2 = value.attempt;
|
|
@@ -421465,7 +421753,7 @@ var init_inbound_dispatch = __esm(async () => {
|
|
|
421465
421753
|
});
|
|
421466
421754
|
|
|
421467
421755
|
// src/websocket/listener/protocol-logging.ts
|
|
421468
|
-
function
|
|
421756
|
+
function isRecord14(value) {
|
|
421469
421757
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
421470
421758
|
}
|
|
421471
421759
|
function formatLogValue(value) {
|
|
@@ -421489,14 +421777,14 @@ function pushField(fields, key2, value, label = key2) {
|
|
|
421489
421777
|
fields.push(`${label}=${formatted}`);
|
|
421490
421778
|
}
|
|
421491
421779
|
function summarizeInputPayload(payload) {
|
|
421492
|
-
if (!
|
|
421780
|
+
if (!isRecord14(payload))
|
|
421493
421781
|
return [];
|
|
421494
421782
|
const fields = [];
|
|
421495
421783
|
pushField(fields, "kind", payload.kind);
|
|
421496
421784
|
if (payload.kind === "create_message") {
|
|
421497
421785
|
pushField(fields, "messages", payload.messages);
|
|
421498
421786
|
pushField(fields, "client_tool_allowlist", payload.client_tool_allowlist);
|
|
421499
|
-
if (
|
|
421787
|
+
if (isRecord14(payload.client_toolset)) {
|
|
421500
421788
|
pushField(fields, "client_toolset.base", payload.client_toolset.base);
|
|
421501
421789
|
pushField(fields, "client_toolset.include", payload.client_toolset.include);
|
|
421502
421790
|
}
|
|
@@ -421513,9 +421801,9 @@ function summarizeRuntimeStartCommand(command) {
|
|
|
421513
421801
|
const fields = [];
|
|
421514
421802
|
pushField(fields, "agent_id", command.agent_id, "agent");
|
|
421515
421803
|
pushField(fields, "conversation_id", command.conversation_id, "conversation");
|
|
421516
|
-
if (
|
|
421804
|
+
if (isRecord14(command.create_agent))
|
|
421517
421805
|
fields.push("create_agent=true");
|
|
421518
|
-
if (
|
|
421806
|
+
if (isRecord14(command.create_conversation)) {
|
|
421519
421807
|
fields.push("create_conversation=true");
|
|
421520
421808
|
}
|
|
421521
421809
|
pushField(fields, "cwd", command.cwd);
|
|
@@ -421524,17 +421812,17 @@ function summarizeRuntimeStartCommand(command) {
|
|
|
421524
421812
|
return fields;
|
|
421525
421813
|
}
|
|
421526
421814
|
function summarizeV2Command(parsed) {
|
|
421527
|
-
if (!
|
|
421815
|
+
if (!isRecord14(parsed) || typeof parsed.type !== "string")
|
|
421528
421816
|
return "unknown";
|
|
421529
421817
|
const fields = [];
|
|
421530
|
-
const runtime =
|
|
421818
|
+
const runtime = isRecord14(parsed.runtime) ? parsed.runtime : null;
|
|
421531
421819
|
if (runtime) {
|
|
421532
421820
|
fields.push(`runtime=${runtime.agent_id ?? "<unknown>"}/${runtime.conversation_id ?? "<unknown>"}`);
|
|
421533
421821
|
}
|
|
421534
421822
|
pushField(fields, "request_id", parsed.request_id);
|
|
421535
421823
|
if (parsed.type === "input") {
|
|
421536
421824
|
fields.push(...summarizeInputPayload(parsed.payload));
|
|
421537
|
-
} else if (parsed.type === "change_device_state" &&
|
|
421825
|
+
} else if (parsed.type === "change_device_state" && isRecord14(parsed.payload)) {
|
|
421538
421826
|
pushField(fields, "mode", parsed.payload.mode);
|
|
421539
421827
|
pushField(fields, "cwd", parsed.payload.cwd);
|
|
421540
421828
|
pushField(fields, "agent_id", parsed.payload.agent_id);
|
|
@@ -421544,7 +421832,7 @@ function summarizeV2Command(parsed) {
|
|
|
421544
421832
|
} else if (parsed.type === "runtime_external_tools_update" && Array.isArray(parsed.updates)) {
|
|
421545
421833
|
fields.push(`updates=${parsed.updates.length}`);
|
|
421546
421834
|
fields.push(`runtimes=${parsed.updates.reduce((count, update3) => {
|
|
421547
|
-
return count + (
|
|
421835
|
+
return count + (isRecord14(update3) && Array.isArray(update3.runtimes) ? update3.runtimes.length : 0);
|
|
421548
421836
|
}, 0)}`);
|
|
421549
421837
|
} else {
|
|
421550
421838
|
for (const key2 of [
|
|
@@ -424403,7 +424691,7 @@ function decodeJwtClaims(token2, sharedSecret) {
|
|
|
424403
424691
|
} catch {
|
|
424404
424692
|
return { error: unauthorized("invalid websocket jwt") };
|
|
424405
424693
|
}
|
|
424406
|
-
if (!
|
|
424694
|
+
if (!isRecord15(header) || header.alg !== "HS256") {
|
|
424407
424695
|
return { error: unauthorized("invalid websocket jwt") };
|
|
424408
424696
|
}
|
|
424409
424697
|
const expectedSignature = createHmac("sha256", sharedSecret).update(`${encodedHeader}.${encodedClaims}`).digest();
|
|
@@ -424441,7 +424729,7 @@ function audienceMatches(actual, expectedAudience) {
|
|
|
424441
424729
|
return false;
|
|
424442
424730
|
}
|
|
424443
424731
|
function isJwtClaims(value) {
|
|
424444
|
-
if (!
|
|
424732
|
+
if (!isRecord15(value) || !Number.isSafeInteger(value.exp)) {
|
|
424445
424733
|
return false;
|
|
424446
424734
|
}
|
|
424447
424735
|
if (value.nbf !== undefined && !Number.isSafeInteger(value.nbf)) {
|
|
@@ -424461,7 +424749,7 @@ function isJwtClaims(value) {
|
|
|
424461
424749
|
}
|
|
424462
424750
|
return true;
|
|
424463
424751
|
}
|
|
424464
|
-
function
|
|
424752
|
+
function isRecord15(value) {
|
|
424465
424753
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
424466
424754
|
}
|
|
424467
424755
|
function base64UrlDecode(value) {
|
|
@@ -444556,8 +444844,8 @@ async function connectMcpServer(config2, options = {}) {
|
|
|
444556
444844
|
return {
|
|
444557
444845
|
content: Array.isArray(result3.content) ? result3.content : [],
|
|
444558
444846
|
...typeof result3.isError === "boolean" ? { isError: result3.isError } : {},
|
|
444559
|
-
...
|
|
444560
|
-
...
|
|
444847
|
+
...isRecord16(result3.structuredContent) ? { structuredContent: result3.structuredContent } : {},
|
|
444848
|
+
...isRecord16(result3._meta) ? { _meta: result3._meta } : {}
|
|
444561
444849
|
};
|
|
444562
444850
|
},
|
|
444563
444851
|
close: async () => {
|
|
@@ -444630,11 +444918,11 @@ function mergeHeaders4(init, headers) {
|
|
|
444630
444918
|
};
|
|
444631
444919
|
}
|
|
444632
444920
|
function normalizeInputSchema(value) {
|
|
444633
|
-
if (
|
|
444921
|
+
if (isRecord16(value) && value.type === "object")
|
|
444634
444922
|
return value;
|
|
444635
444923
|
return { type: "object", properties: {} };
|
|
444636
444924
|
}
|
|
444637
|
-
function
|
|
444925
|
+
function isRecord16(value) {
|
|
444638
444926
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
444639
444927
|
}
|
|
444640
444928
|
var DEFAULT_CLIENT_INFO;
|
|
@@ -444646,7 +444934,7 @@ var init_mcp_client = __esm(() => {
|
|
|
444646
444934
|
init_streamableHttp();
|
|
444647
444935
|
DEFAULT_CLIENT_INFO = {
|
|
444648
444936
|
name: "letta-code",
|
|
444649
|
-
version: "0.33.
|
|
444937
|
+
version: "0.33.5"
|
|
444650
444938
|
};
|
|
444651
444939
|
});
|
|
444652
444940
|
|
|
@@ -447314,7 +447602,7 @@ import {
|
|
|
447314
447602
|
} from "node:fs";
|
|
447315
447603
|
import { tmpdir as tmpdir12 } from "node:os";
|
|
447316
447604
|
import path45 from "node:path";
|
|
447317
|
-
function
|
|
447605
|
+
function isRecord17(value) {
|
|
447318
447606
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
447319
447607
|
}
|
|
447320
447608
|
function isPathInsideOrEqual2(childPath, parentPath) {
|
|
@@ -447330,7 +447618,7 @@ function readPackageJson(packageJsonPath) {
|
|
|
447330
447618
|
} catch (error5) {
|
|
447331
447619
|
throw new Error(`Could not read package.json: ${error5 instanceof Error ? error5.message : String(error5)}`);
|
|
447332
447620
|
}
|
|
447333
|
-
if (!
|
|
447621
|
+
if (!isRecord17(parsed)) {
|
|
447334
447622
|
throw new Error("package.json must be an object");
|
|
447335
447623
|
}
|
|
447336
447624
|
return parsed;
|
|
@@ -447340,7 +447628,7 @@ function formatRepository(repository) {
|
|
|
447340
447628
|
const trimmed2 = repository.trim();
|
|
447341
447629
|
return trimmed2 || undefined;
|
|
447342
447630
|
}
|
|
447343
|
-
if (!
|
|
447631
|
+
if (!isRecord17(repository))
|
|
447344
447632
|
return;
|
|
447345
447633
|
const url2 = repository.url;
|
|
447346
447634
|
if (typeof url2 !== "string")
|
|
@@ -447870,7 +448158,7 @@ function hasRuntimeDependencies(packageJson) {
|
|
|
447870
448158
|
if (!packageJson)
|
|
447871
448159
|
return false;
|
|
447872
448160
|
const dependencies4 = packageJson.dependencies;
|
|
447873
|
-
return
|
|
448161
|
+
return isRecord17(dependencies4) && Object.keys(dependencies4).length > 0;
|
|
447874
448162
|
}
|
|
447875
448163
|
function readPackageJsonIfExists(packageDirectory) {
|
|
447876
448164
|
const packageJsonPath = path45.join(packageDirectory, "package.json");
|
|
@@ -511968,4 +512256,4 @@ function registerBunOAuthFlows() {
|
|
|
511968
512256
|
registerBunOAuthFlows();
|
|
511969
512257
|
await init_src5().then(() => exports_src2);
|
|
511970
512258
|
|
|
511971
|
-
//# debugId=
|
|
512259
|
+
//# debugId=4BF692CA3D7D262964756E2164756E21
|