@elevasis/sdk 1.42.0 → 1.43.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/cli.cjs +16 -75
- package/dist/index.d.ts +265 -140
- package/dist/index.js +15 -74
- package/dist/node/index.d.ts +262 -125
- package/dist/test-utils/index.d.ts +264 -129
- package/dist/test-utils/index.js +441 -905
- package/dist/types/worker/adapters/llm.d.ts +2 -4
- package/dist/worker/index.js +432 -896
- package/package.json +4 -4
- package/reference/claude-config/sync-notes/2026-07-30-login-screen-and-member-provisioning-state.md +114 -0
- package/reference/sdk/platform-tools/index.mdx +5 -6
package/dist/test-utils/index.js
CHANGED
|
@@ -4460,21 +4460,16 @@ function resolveSecurityLevel(config2) {
|
|
|
4460
4460
|
}
|
|
4461
4461
|
|
|
4462
4462
|
// ../core/src/execution/engine/agent/reasoning/prompt-sections/base-actions.ts
|
|
4463
|
-
function buildBaseActionsPrompt(includeMessageAction
|
|
4464
|
-
const actionNames = ["tool-call (call a tool)"];
|
|
4465
|
-
if (includeNavigateKnowledge) {
|
|
4466
|
-
actionNames.push("navigate-knowledge (load knowledge node)");
|
|
4467
|
-
}
|
|
4468
|
-
actionNames.push("complete (finish task)");
|
|
4469
|
-
const actionsList = actionNames.map((name, index2) => `${index2 + 1}. ${name}`).join("\n");
|
|
4470
|
-
const actionCount = actionNames.length;
|
|
4463
|
+
function buildBaseActionsPrompt(includeMessageAction) {
|
|
4471
4464
|
return `# CORE AGENT INSTRUCTIONS
|
|
4472
4465
|
|
|
4473
4466
|
You are an AI agent. Your response is captured as structured output. ${includeMessageAction ? "Three fields are required" : "Two fields are required"} on
|
|
4474
4467
|
every response:
|
|
4475
4468
|
|
|
4476
4469
|
- **reasoning** -- your thought process, as plain prose.
|
|
4477
|
-
- **nextActions** -- the actions to execute
|
|
4470
|
+
- **nextActions** -- the actions to execute: \`tool-call\` to call a tool, or \`complete\` to finish. Tool calls
|
|
4471
|
+
batched into the same iteration run in parallel, and their results appear in your next iteration; without a
|
|
4472
|
+
\`complete\` action, the system iterates again.${includeMessageAction ? `
|
|
4478
4473
|
- **message** -- your reply to the user, as plain prose. This is the ONLY field the user sees.
|
|
4479
4474
|
Whatever you decide to say, it goes here. Use an empty string only when this iteration just calls
|
|
4480
4475
|
tools and you genuinely have nothing to tell the user yet -- an empty message ends the turn in
|
|
@@ -4484,72 +4479,23 @@ every response:
|
|
|
4484
4479
|
and never continue the response envelope in the reasoning text -- nextActions is a separate field
|
|
4485
4480
|
that you fill separately. A response carrying reasoning alone is discarded and retried.
|
|
4486
4481
|
|
|
4487
|
-
## Action Types (${actionCount} available)
|
|
4488
|
-
|
|
4489
|
-
${actionsList}
|
|
4490
|
-
|
|
4491
|
-
**Formats:**
|
|
4492
|
-
- tool-call: { "type": "tool-call", "id": "unique-id", "name": "tool_name", "input": {...} }${includeNavigateKnowledge ? `
|
|
4493
|
-
- navigate-knowledge: { "type": "navigate-knowledge", "id": "unique-id", "nodeId": "node-name" }` : ""}
|
|
4494
|
-
- complete: { "type": "complete" }
|
|
4495
|
-
${includeMessageAction ? `
|
|
4496
|
-
Talking to the user is NOT an action. There is no message action -- put your reply in the
|
|
4497
|
-
**message** field beside nextActions.
|
|
4498
|
-
` : ""}
|
|
4499
|
-
## Execution Flow
|
|
4500
|
-
|
|
4501
|
-
1. You respond with reasoning + actions${includeMessageAction ? " + your message to the user" : ""}
|
|
4502
|
-
2. System executes actions (tool calls run **in parallel**)
|
|
4503
|
-
3. Tool results automatically appear in your next iteration
|
|
4504
|
-
4. You see results and decide: more work needed? Or complete?
|
|
4505
|
-
5. **Without "complete" action, system iterates again**
|
|
4506
|
-
|
|
4507
4482
|
## Rules
|
|
4508
4483
|
|
|
4509
4484
|
- Batch independent tool calls in one iteration (faster execution)
|
|
4510
4485
|
- Dependent operations need separate iterations (tool B needs tool A's result)
|
|
4511
|
-
- "complete"
|
|
4512
|
-
-
|
|
4486
|
+
- "complete" can mix with tool-call when the tool is a fire-and-forget side effect and you do not need its result before ending
|
|
4487
|
+
- Complete when the task finished successfully, a tool returned empty/error results (inform the user first), or you need user input to proceed (ask the question first)
|
|
4488
|
+
- Don't complete when you just called a tool and need its results, or more iterations are needed${includeMessageAction ? `
|
|
4513
4489
|
- Always fill message before completing -- it is the only field the user sees, and completing with it empty ends the turn in silence
|
|
4514
4490
|
- message holds one reply. Write the whole reply in it; do not split a reply across iterations
|
|
4515
4491
|
- When you have your answer, put it in message and include complete in the SAME iteration. Never reply on one iteration then complete on a later one
|
|
4516
4492
|
- Never repeat or rephrase the same answer across iterations. One clear answer, then complete` : ""}
|
|
4517
4493
|
|
|
4518
|
-
**Use "complete" when:**
|
|
4519
|
-
- Task finished successfully
|
|
4520
|
-
- Tool returned empty/error results (inform user first)
|
|
4521
|
-
- You need user input to proceed (ask question first)
|
|
4522
|
-
|
|
4523
|
-
**Don't use "complete" when:**
|
|
4524
|
-
- You just called a tool and need its results
|
|
4525
|
-
- You used navigate-knowledge and need the newly loaded knowledge in the next iteration
|
|
4526
|
-
- More iterations are needed
|
|
4527
|
-
|
|
4528
4494
|
## Examples
|
|
4529
4495
|
|
|
4530
4496
|
Each example shows the field values, not a JSON document to copy.
|
|
4531
4497
|
|
|
4532
|
-
### Example
|
|
4533
|
-
- reasoning: Simple greeting, no tools needed.${includeMessageAction ? "\n- message: Hi! How can I help?" : ""}
|
|
4534
|
-
- nextActions: [{ "type": "complete" }]
|
|
4535
|
-
|
|
4536
|
-
### Example 2: Tool Usage (Two Iterations)
|
|
4537
|
-
|
|
4538
|
-
**Iteration 1 - Call tool (NO complete - waiting for results):**
|
|
4539
|
-
- reasoning: User asked for time. Calling get_time tool.${includeMessageAction ? "\n- message: Checking the time..." : ""}
|
|
4540
|
-
- nextActions: [{ "type": "tool-call", "id": "t1", "name": "get_time", "input": { "timezone": "UTC" } }]
|
|
4541
|
-
|
|
4542
|
-
**Iteration 2 - Tool result received, now complete:**
|
|
4543
|
-
- reasoning: Got time result: 12:00 PM UTC. Task done.${includeMessageAction ? "\n- message: The current time is 12:00 PM UTC." : ""}
|
|
4544
|
-
- nextActions: [{ "type": "complete" }]
|
|
4545
|
-
|
|
4546
|
-
### Example 3: Parallel Tool Calls (Independent Operations)
|
|
4547
|
-
When tools don't depend on each other, batch them for faster execution.
|
|
4548
|
-
|
|
4549
|
-
- reasoning: User wants time AND weather. Independent operations - calling both in parallel.${includeMessageAction ? "\n- message: Getting time and weather..." : ""}
|
|
4550
|
-
- nextActions: [{ "type": "tool-call", "id": "t1", "name": "get_time", "input": {} }, { "type": "tool-call", "id": "w1", "name": "get_weather", "input": { "city": "NYC" } }]
|
|
4551
|
-
|
|
4552
|
-
### Example 4: Dependent Operations (Separate Iterations Required)
|
|
4498
|
+
### Example: Dependent Operations (Separate Iterations Required)
|
|
4553
4499
|
|
|
4554
4500
|
**\u274C WRONG - Cannot batch dependent operations:**
|
|
4555
4501
|
- nextActions: [{ "type": "tool-call", "id": "1", "name": "search_user", "input": { "email": "user@example.com" } }, { "type": "tool-call", "id": "2", "name": "update_user", "input": { "userId": "???" } }]
|
|
@@ -4563,144 +4509,24 @@ Problem: update_user needs userId from search_user result!
|
|
|
4563
4509
|
**\u2705 CORRECT - Iteration 2 (use the result):**
|
|
4564
4510
|
- reasoning: Found userId: user_123. Now can update.
|
|
4565
4511
|
- nextActions: [{ "type": "tool-call", "id": "2", "name": "update_user", "input": { "userId": "user_123", "name": "New Name" } }]
|
|
4566
|
-
|
|
4567
|
-
---
|
|
4568
|
-
|
|
4569
|
-
These are your CORE INSTRUCTIONS. Additional context follows below.
|
|
4570
4512
|
`;
|
|
4571
4513
|
}
|
|
4572
4514
|
|
|
4573
|
-
// ../core/src/execution/engine/agent/reasoning/prompt-sections/knowledge-map.ts
|
|
4574
|
-
function buildKnowledgeMapPrompt(knowledgeMap) {
|
|
4575
|
-
if (!knowledgeMap || Object.keys(knowledgeMap.nodes).length === 0) {
|
|
4576
|
-
return "";
|
|
4577
|
-
}
|
|
4578
|
-
let section = "## Knowledge Map\n\n";
|
|
4579
|
-
section += "Knowledge maps provide on-demand access to specialized capabilities. ";
|
|
4580
|
-
section += "Each node contains domain-specific instructions and tools.\n\n";
|
|
4581
|
-
section += "**CRITICAL**: After navigating to a node, tools become available in the **NEXT iteration**. ";
|
|
4582
|
-
section += "Do NOT attempt to use tools in the same iteration as navigation.\n\n";
|
|
4583
|
-
const loadedNodes = [];
|
|
4584
|
-
const unloadedNodes = [];
|
|
4585
|
-
Object.values(knowledgeMap.nodes).forEach((node) => {
|
|
4586
|
-
if (node.loaded && node.prompt) {
|
|
4587
|
-
loadedNodes.push(node);
|
|
4588
|
-
} else {
|
|
4589
|
-
unloadedNodes.push(node);
|
|
4590
|
-
}
|
|
4591
|
-
});
|
|
4592
|
-
if (loadedNodes.length > 0) {
|
|
4593
|
-
section += "### Loaded Knowledge\n\n";
|
|
4594
|
-
section += "These nodes are active - their tools are available now:\n\n";
|
|
4595
|
-
loadedNodes.forEach((node) => {
|
|
4596
|
-
section += `**${node.id}**
|
|
4597
|
-
${node.prompt}
|
|
4598
|
-
|
|
4599
|
-
`;
|
|
4600
|
-
});
|
|
4601
|
-
}
|
|
4602
|
-
if (unloadedNodes.length > 0) {
|
|
4603
|
-
section += "### Available to Load\n\n";
|
|
4604
|
-
unloadedNodes.forEach((node) => {
|
|
4605
|
-
section += `- **${node.id}**: ${node.description}
|
|
4606
|
-
`;
|
|
4607
|
-
});
|
|
4608
|
-
section += "\n### How to Navigate\n\n";
|
|
4609
|
-
section += "Put a navigate-knowledge entry in your nextActions:\n";
|
|
4610
|
-
section += '`{ "type": "navigate-knowledge", "id": "unique-id", "nodeId": "node-id" }`\n\n';
|
|
4611
|
-
section += "### Typical Workflow\n\n";
|
|
4612
|
-
section += "**Iteration 1 - Navigate to load knowledge:**\n";
|
|
4613
|
-
section += "- reasoning: I need [domain] capabilities to accomplish this task.\n";
|
|
4614
|
-
section += '- nextActions: [{ "type": "navigate-knowledge", "id": "nav-1", "nodeId": "[node-id]" }]\n\n';
|
|
4615
|
-
section += "**Iteration 2 - Use newly available tools:**\n";
|
|
4616
|
-
section += "- reasoning: Now I have [domain] tools. Using [tool_name] to [action].\n";
|
|
4617
|
-
section += '- nextActions: [{ "type": "tool-call", "id": "t1", "name": "[tool_name]", "input": { ... } }]\n\n';
|
|
4618
|
-
section += "**Note:** Loaded knowledge persists across conversation turns. ";
|
|
4619
|
-
section += "Previously loaded nodes remain available without re-navigation.\n";
|
|
4620
|
-
}
|
|
4621
|
-
return section + "\n";
|
|
4622
|
-
}
|
|
4623
|
-
|
|
4624
4515
|
// ../core/src/execution/engine/agent/reasoning/prompt-sections/tools.ts
|
|
4625
4516
|
function buildToolsPrompt(tools) {
|
|
4626
4517
|
if (tools.length === 0) {
|
|
4627
4518
|
return "";
|
|
4628
4519
|
}
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
tools.forEach((tool) => {
|
|
4632
|
-
section += `### ${tool.name}
|
|
4633
|
-
`;
|
|
4634
|
-
section += `${tool.description}
|
|
4635
|
-
`;
|
|
4636
|
-
section += `Input schema: ${JSON.stringify(tool.inputSchema, null, 2)}
|
|
4637
|
-
|
|
4638
|
-
`;
|
|
4639
|
-
});
|
|
4640
|
-
section += "To call a tool, return a tool-call action:\n";
|
|
4641
|
-
section += '{\n "type": "tool-call",\n "id": "unique-id",\n "name": "tool-name",\n "input": { /* tool input matching schema */ }\n}\n\n';
|
|
4642
|
-
section += "**IMPORTANT RULES:**\n";
|
|
4643
|
-
section += '1. "complete" CANNOT mix with navigate-knowledge actions in the same response\n';
|
|
4644
|
-
section += '2. The "message" field CAN be filled on the same response that completes - always pair your final message with complete in the same iteration\n';
|
|
4645
|
-
section += '3. "complete" CAN mix with fire-and-forget tool-call actions when you do not need their results\n';
|
|
4646
|
-
section += "4. To use tools and inspect their results, return ONLY tool-call actions, then wait for results in the next iteration\n";
|
|
4647
|
-
section += "5. After receiving tool results, you can either call more tools OR complete with final answer\n";
|
|
4648
|
-
section += "6. navigate-knowledge actions load new capabilities - tools become available in the next iteration\n";
|
|
4649
|
-
return section + "\n";
|
|
4650
|
-
}
|
|
4651
|
-
|
|
4652
|
-
// ../core/src/execution/engine/agent/reasoning/prompt-sections/memory.ts
|
|
4653
|
-
function buildMemoryPrompt(memoryStatus, preferences) {
|
|
4654
|
-
return `## Memory Management
|
|
4655
|
-
|
|
4656
|
-
You have control over session memory. Use memoryOps to manage critical information:
|
|
4657
|
-
|
|
4658
|
-
\`memoryOps\` is a field of your structured response, not a document you write out. Its \`set\` is a
|
|
4659
|
-
LIST of entries, each with a \`key\` and a \`value\` \u2014 not an object keyed by name.
|
|
4660
|
-
|
|
4661
|
-
**SET critical information** \u2014 \`set\` entries look like:
|
|
4662
|
-
|
|
4663
|
-
- key \`customer_account\`, value \`Account #12345, Premium tier, expires 2026-03-15\`
|
|
4664
|
-
- key \`original_request\`, value \`Fix broken widget\`
|
|
4665
|
-
|
|
4666
|
-
**DELETE outdated information** \u2014 \`delete\` is a list of key names:
|
|
4667
|
-
|
|
4668
|
-
- \`old_address\`, \`cancelled_order\`
|
|
4669
|
-
|
|
4670
|
-
**When to persist:**
|
|
4671
|
-
- Memory at ${memoryStatus.historyPercent}%: ${memoryStatus.historyPercent >= 80 ? "Proactively persist important context NOW (auto-compaction at 100%)" : "Normal operation"}
|
|
4672
|
-
- Session keys at ${memoryStatus.sessionMemoryKeys}/${memoryStatus.sessionMemoryLimit}: Delete outdated keys before adding new ones
|
|
4673
|
-
- Always: Persist critical data that should survive memory compaction
|
|
4674
|
-
|
|
4675
|
-
**IMPORTANT - System-Managed Memory:**
|
|
4676
|
-
Do NOT update these keys via memoryOps (managed automatically by tools/actions):
|
|
4677
|
-
- notion-pages-cache (managed by Notion tools)
|
|
4678
|
-
- knowledge-map-state (managed by navigate-knowledge)
|
|
4679
|
-
|
|
4680
|
-
Attempting to update system-managed keys will be rejected. Use tools to update their caches.
|
|
4681
|
-
${preferences ? `
|
|
4682
|
-
**Agent-Specific Guidance:**
|
|
4683
|
-
${preferences}
|
|
4684
|
-
` : ""}
|
|
4685
|
-
Framework auto-compacts history at 100% token budget.
|
|
4686
|
-
You control WHAT to remember. Framework controls HOW compaction works.
|
|
4687
|
-
|
|
4688
|
-
`;
|
|
4520
|
+
return tools.map((tool) => `### ${tool.name}
|
|
4521
|
+
${tool.description}`).join("\n\n") + "\n";
|
|
4689
4522
|
}
|
|
4690
4523
|
|
|
4691
4524
|
// ../core/src/execution/engine/agent/reasoning/prompt-sections/completion.ts
|
|
4692
4525
|
function buildCompletionPrompt(outputSchema) {
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
section += '```json\n{ "type": "complete" }\n```\n\n';
|
|
4696
|
-
if (outputSchema) {
|
|
4697
|
-
section += "After task completion, the final output will be generated and will need to include:\n";
|
|
4698
|
-
section += describeOutputSchema(outputSchema);
|
|
4699
|
-
section += "\n\nDuring task execution, focus on gathering all necessary information.";
|
|
4700
|
-
} else {
|
|
4701
|
-
section += "This is a side-effect agent (no output generation). Focus on performing the requested actions.";
|
|
4526
|
+
if (!outputSchema) {
|
|
4527
|
+
return "";
|
|
4702
4528
|
}
|
|
4703
|
-
return
|
|
4529
|
+
return "When you complete the task, the final output will be generated and will need to include:\n" + describeOutputSchema(outputSchema) + "\n\nDuring task execution, focus on gathering all necessary information.\n";
|
|
4704
4530
|
}
|
|
4705
4531
|
function describeOutputSchema(schema) {
|
|
4706
4532
|
const jsonSchema = zodToJsonSchema(schema, {
|
|
@@ -4717,47 +4543,57 @@ function buildSystemPrompt(agentPrompt, options) {
|
|
|
4717
4543
|
if (securitySection) {
|
|
4718
4544
|
sections.push(securitySection);
|
|
4719
4545
|
}
|
|
4720
|
-
sections.push(buildBaseActionsPrompt(options.
|
|
4721
|
-
const knowledgeMapSection = buildKnowledgeMapPrompt(options.knowledgeMap);
|
|
4722
|
-
if (knowledgeMapSection) {
|
|
4723
|
-
sections.push(knowledgeMapSection);
|
|
4724
|
-
}
|
|
4546
|
+
sections.push(buildBaseActionsPrompt(options.capabilities.messageAction));
|
|
4725
4547
|
const toolsSection = buildToolsPrompt(options.tools);
|
|
4726
4548
|
if (toolsSection) {
|
|
4727
4549
|
sections.push(toolsSection);
|
|
4728
4550
|
}
|
|
4729
|
-
|
|
4730
|
-
|
|
4551
|
+
const completionSection = buildCompletionPrompt(options.outputSchema);
|
|
4552
|
+
if (completionSection) {
|
|
4553
|
+
sections.push(completionSection);
|
|
4731
4554
|
}
|
|
4732
|
-
sections.push(buildCompletionPrompt(options.outputSchema));
|
|
4733
4555
|
sections.push("---\n");
|
|
4734
4556
|
sections.push("# AGENT-SPECIFIC INSTRUCTIONS\n\n");
|
|
4735
|
-
sections.push(
|
|
4557
|
+
sections.push(
|
|
4558
|
+
options.memoryPreferences ? `${agentPrompt}
|
|
4559
|
+
|
|
4560
|
+
**Agent-Specific Memory Guidance:**
|
|
4561
|
+
${options.memoryPreferences}
|
|
4562
|
+
` : agentPrompt
|
|
4563
|
+
);
|
|
4736
4564
|
return sections.join("\n");
|
|
4737
4565
|
}
|
|
4566
|
+
var toolInputSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
4567
|
+
function getToolInputSchema(tool) {
|
|
4568
|
+
let schema = toolInputSchemaCache.get(tool);
|
|
4569
|
+
if (schema === void 0) {
|
|
4570
|
+
schema = zodToJsonSchema(tool.inputSchema, { $refStrategy: "none" });
|
|
4571
|
+
toolInputSchemaCache.set(tool, schema);
|
|
4572
|
+
}
|
|
4573
|
+
return schema;
|
|
4574
|
+
}
|
|
4738
4575
|
function buildReasoningRequest(iterationContext) {
|
|
4739
4576
|
const tools = Array.from(iterationContext.toolRegistry.values());
|
|
4740
4577
|
const toolDefinitions = tools.map((tool) => ({
|
|
4741
4578
|
name: tool.name,
|
|
4742
4579
|
description: tool.description,
|
|
4743
|
-
inputSchema:
|
|
4580
|
+
inputSchema: getToolInputSchema(tool)
|
|
4744
4581
|
}));
|
|
4745
|
-
|
|
4746
|
-
const
|
|
4747
|
-
|
|
4748
|
-
|
|
4582
|
+
iterationContext.memoryManager.enforceHardLimits();
|
|
4583
|
+
const capabilities = {
|
|
4584
|
+
// Explicit session support declaration controls whether message action is available.
|
|
4585
|
+
messageAction: !!iterationContext.config.sessionCapable,
|
|
4586
|
+
// memoryOps is available whenever the agent declared memory preferences.
|
|
4587
|
+
memoryOps: !!iterationContext.config.memoryPreferences
|
|
4588
|
+
};
|
|
4749
4589
|
const securityLevel = resolveSecurityLevel(iterationContext.config);
|
|
4750
4590
|
const systemPrompt = buildSystemPrompt(iterationContext.config.systemPrompt, {
|
|
4751
4591
|
securityLevel,
|
|
4752
|
-
|
|
4753
|
-
includeNavigateKnowledge: hasKnowledgeMap,
|
|
4754
|
-
knowledgeMap: iterationContext.knowledgeMap,
|
|
4592
|
+
capabilities,
|
|
4755
4593
|
tools: toolDefinitions,
|
|
4756
|
-
memoryStatus,
|
|
4757
4594
|
outputSchema: iterationContext.contract.outputSchema,
|
|
4758
4595
|
memoryPreferences: iterationContext.config.memoryPreferences
|
|
4759
4596
|
});
|
|
4760
|
-
iterationContext.memoryManager.enforceHardLimits();
|
|
4761
4597
|
return {
|
|
4762
4598
|
systemPrompt,
|
|
4763
4599
|
tools: toolDefinitions,
|
|
@@ -4773,9 +4609,7 @@ function buildReasoningRequest(iterationContext) {
|
|
|
4773
4609
|
securityLevel,
|
|
4774
4610
|
// A session agent gets its own conversation. Non-session executions have none.
|
|
4775
4611
|
conversationHistory: iterationContext.executionContext.conversationHistory ?? [],
|
|
4776
|
-
|
|
4777
|
-
includeNavigateKnowledge: hasKnowledgeMap,
|
|
4778
|
-
includeMemoryOps
|
|
4612
|
+
capabilities
|
|
4779
4613
|
};
|
|
4780
4614
|
}
|
|
4781
4615
|
var ToolCallActionSchema = z.object({
|
|
@@ -4792,17 +4626,56 @@ var MessageActionSchema = z.object({
|
|
|
4792
4626
|
type: z.literal("message"),
|
|
4793
4627
|
text: z.string()
|
|
4794
4628
|
});
|
|
4795
|
-
var NavigateKnowledgeActionSchema = z.object({
|
|
4796
|
-
type: z.literal("navigate-knowledge"),
|
|
4797
|
-
id: z.string(),
|
|
4798
|
-
nodeId: z.string()
|
|
4799
|
-
});
|
|
4800
4629
|
var AgentActionSchema = z.discriminatedUnion("type", [
|
|
4801
4630
|
ToolCallActionSchema,
|
|
4802
4631
|
CompleteActionSchema,
|
|
4803
|
-
MessageActionSchema
|
|
4804
|
-
NavigateKnowledgeActionSchema
|
|
4632
|
+
MessageActionSchema
|
|
4805
4633
|
]);
|
|
4634
|
+
|
|
4635
|
+
// ../core/src/execution/engine/llm/errors.ts
|
|
4636
|
+
var LLMError = class extends ExecutionError {
|
|
4637
|
+
type = "llm_error";
|
|
4638
|
+
severity = "warning";
|
|
4639
|
+
category = "llm";
|
|
4640
|
+
constructor(message, context) {
|
|
4641
|
+
super(message, context);
|
|
4642
|
+
}
|
|
4643
|
+
};
|
|
4644
|
+
var InsufficientTokensError = class extends LLMError {
|
|
4645
|
+
type = "insufficient_tokens";
|
|
4646
|
+
severity = "critical";
|
|
4647
|
+
constructor(message, context) {
|
|
4648
|
+
super(message, context);
|
|
4649
|
+
}
|
|
4650
|
+
/** The model configuration is short of what the request needs; retrying sends the identical
|
|
4651
|
+
* request into the identical shortfall. */
|
|
4652
|
+
isRetryable() {
|
|
4653
|
+
return false;
|
|
4654
|
+
}
|
|
4655
|
+
};
|
|
4656
|
+
var LLMResponseParseError = class extends LLMError {
|
|
4657
|
+
type = "llm_response_parse_error";
|
|
4658
|
+
severity = "warning";
|
|
4659
|
+
constructor(message, context) {
|
|
4660
|
+
super(message, context);
|
|
4661
|
+
}
|
|
4662
|
+
/** JSON parse failures are transient LLM errors -- the same prompt can produce well-formed JSON on
|
|
4663
|
+
* the next attempt. This is also the one `isRetryable()` verdict `isRetryableError` had to special-case
|
|
4664
|
+
* ahead of everything else before it consulted the typed contract at all. */
|
|
4665
|
+
isRetryable() {
|
|
4666
|
+
return true;
|
|
4667
|
+
}
|
|
4668
|
+
};
|
|
4669
|
+
var ModelConfigError = class extends ExecutionError {
|
|
4670
|
+
constructor(message, field, model, context) {
|
|
4671
|
+
super(message, { ...context, field, model });
|
|
4672
|
+
this.field = field;
|
|
4673
|
+
this.model = model;
|
|
4674
|
+
}
|
|
4675
|
+
type = "model_config_error";
|
|
4676
|
+
severity = "warning";
|
|
4677
|
+
category = "validation";
|
|
4678
|
+
};
|
|
4806
4679
|
var GPT5OptionsSchema = z.object({
|
|
4807
4680
|
reasoning_effort: z.enum(["minimal", "low", "medium", "high"]).optional(),
|
|
4808
4681
|
verbosity: z.enum(["low", "medium", "high"]).optional()
|
|
@@ -4842,19 +4715,6 @@ var OpenRouterConfigSchema = z.object({
|
|
|
4842
4715
|
topP: z.number().min(0).max(1).optional(),
|
|
4843
4716
|
modelOptions: OpenRouterOptionsSchema.optional()
|
|
4844
4717
|
});
|
|
4845
|
-
var GoogleOptionsSchema = z.object({
|
|
4846
|
-
/** Thinking level for Gemini 3 models (controls reasoning depth) */
|
|
4847
|
-
thinkingLevel: z.enum(["minimal", "low", "medium", "high"]).optional()
|
|
4848
|
-
});
|
|
4849
|
-
var GoogleConfigSchema = z.object({
|
|
4850
|
-
model: z.enum(["gemini-3-flash-preview", "gemini-3.1-flash-lite-preview"]),
|
|
4851
|
-
provider: z.literal("google"),
|
|
4852
|
-
apiKey: z.string(),
|
|
4853
|
-
temperature: z.number().min(0).max(2).optional(),
|
|
4854
|
-
maxOutputTokens: z.number().min(500).optional(),
|
|
4855
|
-
topP: z.number().min(0).max(1).optional(),
|
|
4856
|
-
modelOptions: GoogleOptionsSchema.optional()
|
|
4857
|
-
});
|
|
4858
4718
|
var AnthropicOptionsSchema = z.object({}).strict();
|
|
4859
4719
|
var AnthropicStandardConfigSchema = z.object({
|
|
4860
4720
|
model: z.enum(["claude-haiku-4-5-20251001", "claude-haiku-4-5"]),
|
|
@@ -4948,31 +4808,6 @@ var MODEL_INFO = {
|
|
|
4948
4808
|
category: "standard",
|
|
4949
4809
|
configSchema: OpenRouterConfigSchema
|
|
4950
4810
|
},
|
|
4951
|
-
// Google Gemini Models (direct SDK access via @google/genai)
|
|
4952
|
-
"gemini-3-flash-preview": {
|
|
4953
|
-
inputCostPer1M: 50,
|
|
4954
|
-
// $0.50 per 1M tokens
|
|
4955
|
-
outputCostPer1M: 300,
|
|
4956
|
-
// $3.00 per 1M tokens
|
|
4957
|
-
minTokens: 4e3,
|
|
4958
|
-
recommendedTokens: 8e3,
|
|
4959
|
-
maxTokens: 1e6,
|
|
4960
|
-
// 1M context window
|
|
4961
|
-
category: "standard",
|
|
4962
|
-
configSchema: GoogleConfigSchema
|
|
4963
|
-
},
|
|
4964
|
-
"gemini-3.1-flash-lite-preview": {
|
|
4965
|
-
inputCostPer1M: 25,
|
|
4966
|
-
// $0.25 per 1M tokens
|
|
4967
|
-
outputCostPer1M: 150,
|
|
4968
|
-
// $1.50 per 1M tokens
|
|
4969
|
-
minTokens: 4e3,
|
|
4970
|
-
recommendedTokens: 8e3,
|
|
4971
|
-
maxTokens: 1e6,
|
|
4972
|
-
// 1M context window
|
|
4973
|
-
category: "standard",
|
|
4974
|
-
configSchema: GoogleConfigSchema
|
|
4975
|
-
},
|
|
4976
4811
|
// Anthropic Claude Models (direct SDK access via @anthropic-ai/sdk)
|
|
4977
4812
|
"claude-opus-5": {
|
|
4978
4813
|
inputCostPer1M: 500,
|
|
@@ -5029,50 +4864,18 @@ var MODEL_INFO = {
|
|
|
5029
4864
|
configSchema: AnthropicConfigSchema
|
|
5030
4865
|
}
|
|
5031
4866
|
};
|
|
4867
|
+
var MODEL_KEYS_BY_SPECIFICITY = Object.keys(MODEL_INFO).sort((a3, b2) => b2.length - a3.length);
|
|
5032
4868
|
function getModelInfo(model) {
|
|
5033
4869
|
if (model in MODEL_INFO) {
|
|
5034
4870
|
return MODEL_INFO[model];
|
|
5035
4871
|
}
|
|
5036
|
-
for (const
|
|
4872
|
+
for (const knownModel of MODEL_KEYS_BY_SPECIFICITY) {
|
|
5037
4873
|
if (model.startsWith(knownModel)) {
|
|
5038
|
-
return
|
|
4874
|
+
return MODEL_INFO[knownModel];
|
|
5039
4875
|
}
|
|
5040
4876
|
}
|
|
5041
4877
|
return void 0;
|
|
5042
4878
|
}
|
|
5043
|
-
|
|
5044
|
-
// ../core/src/execution/engine/llm/errors.ts
|
|
5045
|
-
var LLMError = class extends ExecutionError {
|
|
5046
|
-
type = "llm_error";
|
|
5047
|
-
severity = "warning";
|
|
5048
|
-
category = "llm";
|
|
5049
|
-
constructor(message, context) {
|
|
5050
|
-
super(message, context);
|
|
5051
|
-
}
|
|
5052
|
-
isRetryable() {
|
|
5053
|
-
return true;
|
|
5054
|
-
}
|
|
5055
|
-
};
|
|
5056
|
-
var InsufficientTokensError = class extends LLMError {
|
|
5057
|
-
type = "insufficient_tokens";
|
|
5058
|
-
severity = "critical";
|
|
5059
|
-
constructor(message, context) {
|
|
5060
|
-
super(message, context);
|
|
5061
|
-
}
|
|
5062
|
-
isRetryable() {
|
|
5063
|
-
return false;
|
|
5064
|
-
}
|
|
5065
|
-
};
|
|
5066
|
-
var ModelConfigError = class extends ExecutionError {
|
|
5067
|
-
constructor(message, field, model, context) {
|
|
5068
|
-
super(message, { ...context, field, model });
|
|
5069
|
-
this.field = field;
|
|
5070
|
-
this.model = model;
|
|
5071
|
-
}
|
|
5072
|
-
type = "model_config_error";
|
|
5073
|
-
severity = "warning";
|
|
5074
|
-
category = "validation";
|
|
5075
|
-
};
|
|
5076
4879
|
function validateModelConfig(config2) {
|
|
5077
4880
|
const model = config2.model;
|
|
5078
4881
|
if (!model) {
|
|
@@ -5094,79 +4897,32 @@ function validateModelConfig(config2) {
|
|
|
5094
4897
|
}
|
|
5095
4898
|
}
|
|
5096
4899
|
|
|
5097
|
-
// ../core/src/execution/engine/
|
|
5098
|
-
var
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
}
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
constructor(message, context) {
|
|
5111
|
-
super(message, context);
|
|
5112
|
-
}
|
|
5113
|
-
};
|
|
5114
|
-
var AgentCompletionError = class extends ExecutionError {
|
|
5115
|
-
type = "agent_completion_error";
|
|
5116
|
-
severity = "warning";
|
|
5117
|
-
category = "agent";
|
|
5118
|
-
constructor(message, context) {
|
|
5119
|
-
super(message, context);
|
|
5120
|
-
}
|
|
5121
|
-
};
|
|
5122
|
-
var AgentOutputValidationError = class extends ExecutionError {
|
|
5123
|
-
type = "agent_output_validation_error";
|
|
5124
|
-
severity = "info";
|
|
5125
|
-
category = "validation";
|
|
5126
|
-
constructor(message, context) {
|
|
5127
|
-
super(message, context);
|
|
5128
|
-
}
|
|
5129
|
-
};
|
|
5130
|
-
var AgentMaxIterationsError = class extends ExecutionError {
|
|
5131
|
-
type = "agent_max_iterations_error";
|
|
5132
|
-
severity = "critical";
|
|
5133
|
-
category = "agent";
|
|
5134
|
-
constructor(message, context) {
|
|
5135
|
-
super(message, context);
|
|
5136
|
-
}
|
|
5137
|
-
};
|
|
5138
|
-
var AgentTimeoutError = class extends ExecutionError {
|
|
5139
|
-
type = "agent_timeout_error";
|
|
5140
|
-
severity = "critical";
|
|
5141
|
-
category = "agent";
|
|
5142
|
-
constructor(message, context) {
|
|
5143
|
-
super(message, context);
|
|
5144
|
-
}
|
|
5145
|
-
};
|
|
5146
|
-
var AgentCancellationError = class extends ExecutionError {
|
|
5147
|
-
type = "agent_cancellation_error";
|
|
5148
|
-
severity = "warning";
|
|
5149
|
-
category = "agent";
|
|
5150
|
-
constructor(message, context) {
|
|
5151
|
-
super(message, context);
|
|
5152
|
-
}
|
|
5153
|
-
};
|
|
5154
|
-
var AgentStalledError = class extends ExecutionError {
|
|
5155
|
-
type = "agent_stalled_error";
|
|
5156
|
-
severity = "critical";
|
|
5157
|
-
category = "agent";
|
|
5158
|
-
constructor(message, context) {
|
|
5159
|
-
super(message, context);
|
|
4900
|
+
// ../core/src/execution/engine/llm/token-validation.ts
|
|
4901
|
+
var UNKNOWN_MODEL_MIN_TOKENS = 2e3;
|
|
4902
|
+
function validateTokenConfiguration(model, maxOutputTokens) {
|
|
4903
|
+
const modelInfo = getModelInfo(model);
|
|
4904
|
+
const configured = maxOutputTokens || 1e3;
|
|
4905
|
+
if (!modelInfo) {
|
|
4906
|
+
if (configured < UNKNOWN_MODEL_MIN_TOKENS) {
|
|
4907
|
+
throw new InsufficientTokensError(
|
|
4908
|
+
`Unknown model '${model}' requires at least 2000 tokens (conservative default), but only ${configured} configured.`,
|
|
4909
|
+
{ model, required: UNKNOWN_MODEL_MIN_TOKENS, configured }
|
|
4910
|
+
);
|
|
4911
|
+
}
|
|
4912
|
+
return;
|
|
5160
4913
|
}
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
4914
|
+
if (configured < modelInfo.minTokens) {
|
|
4915
|
+
throw new InsufficientTokensError(
|
|
4916
|
+
`Model ${model} requires at least ${modelInfo.minTokens} tokens, but only ${configured} configured. ${modelInfo.category === "reasoning" ? "Reasoning models need more tokens to generate both internal reasoning and output." : ""}`,
|
|
4917
|
+
{
|
|
4918
|
+
model,
|
|
4919
|
+
required: modelInfo.minTokens,
|
|
4920
|
+
recommended: modelInfo.recommendedTokens,
|
|
4921
|
+
configured
|
|
4922
|
+
}
|
|
4923
|
+
);
|
|
5168
4924
|
}
|
|
5169
|
-
}
|
|
4925
|
+
}
|
|
5170
4926
|
|
|
5171
4927
|
// ../core/src/execution/engine/llm/flow-debug.ts
|
|
5172
4928
|
var enabled;
|
|
@@ -5191,47 +4947,7 @@ function preview(text, n2 = 120) {
|
|
|
5191
4947
|
return { len: text.length, head: text.slice(0, n2) };
|
|
5192
4948
|
}
|
|
5193
4949
|
|
|
5194
|
-
// ../core/src/execution/engine/agent/reasoning/adapters/
|
|
5195
|
-
var MemoryKeyValuePairSchema = z.object({ key: z.string(), value: z.any() });
|
|
5196
|
-
var MemorySetSchema = z.union([z.record(z.string(), z.any()), z.array(MemoryKeyValuePairSchema)]).transform((value) => {
|
|
5197
|
-
if (!Array.isArray(value)) return value;
|
|
5198
|
-
return Object.fromEntries(value.map(({ key, value: v2 }) => [key, v2]));
|
|
5199
|
-
});
|
|
5200
|
-
var MemoryOperationsSchema = z.object({
|
|
5201
|
-
set: MemorySetSchema.optional(),
|
|
5202
|
-
// Accept any value type - framework will stringify
|
|
5203
|
-
delete: z.array(z.string()).optional()
|
|
5204
|
-
});
|
|
5205
|
-
var AgentIterationOutputSchema = z.object({
|
|
5206
|
-
reasoning: z.string(),
|
|
5207
|
-
message: z.string().optional(),
|
|
5208
|
-
memoryOps: MemoryOperationsSchema.optional(),
|
|
5209
|
-
nextActions: z.array(AgentActionSchema)
|
|
5210
|
-
});
|
|
5211
|
-
function validateTokenConfiguration(model, maxOutputTokens) {
|
|
5212
|
-
const modelInfo = getModelInfo(model);
|
|
5213
|
-
const configured = maxOutputTokens || 1e3;
|
|
5214
|
-
if (!modelInfo) {
|
|
5215
|
-
if (configured < 2e3) {
|
|
5216
|
-
throw new InsufficientTokensError(
|
|
5217
|
-
`Unknown model '${model}' requires at least 2000 tokens (conservative default), but only ${configured} configured.`,
|
|
5218
|
-
{ model, required: 2e3, configured }
|
|
5219
|
-
);
|
|
5220
|
-
}
|
|
5221
|
-
return;
|
|
5222
|
-
}
|
|
5223
|
-
if (configured < modelInfo.minTokens) {
|
|
5224
|
-
throw new InsufficientTokensError(
|
|
5225
|
-
`Model ${model} requires at least ${modelInfo.minTokens} tokens, but only ${configured} configured. ${modelInfo.category === "reasoning" ? "Reasoning models need more tokens to generate both internal reasoning and output." : ""}`,
|
|
5226
|
-
{
|
|
5227
|
-
model,
|
|
5228
|
-
required: modelInfo.minTokens,
|
|
5229
|
-
recommended: modelInfo.recommendedTokens,
|
|
5230
|
-
configured
|
|
5231
|
-
}
|
|
5232
|
-
);
|
|
5233
|
-
}
|
|
5234
|
-
}
|
|
4950
|
+
// ../core/src/execution/engine/agent/reasoning/adapters/messages.ts
|
|
5235
4951
|
function buildUntrustedDataPolicy(securityLevel) {
|
|
5236
4952
|
if (securityLevel === "none") return "";
|
|
5237
4953
|
if (securityLevel === "hardened") {
|
|
@@ -5253,6 +4969,101 @@ ${memory.framing}` : memory.framing },
|
|
|
5253
4969
|
}
|
|
5254
4970
|
return messages;
|
|
5255
4971
|
}
|
|
4972
|
+
|
|
4973
|
+
// ../core/src/execution/engine/agent/reasoning/adapters/response-schema.ts
|
|
4974
|
+
function buildIterationResponseSchema(tools, capabilities) {
|
|
4975
|
+
const actionSchemas = [];
|
|
4976
|
+
for (const tool of tools) {
|
|
4977
|
+
actionSchemas.push({
|
|
4978
|
+
type: "object",
|
|
4979
|
+
properties: {
|
|
4980
|
+
type: { type: "string", enum: ["tool-call"] },
|
|
4981
|
+
id: { type: "string" },
|
|
4982
|
+
name: { type: "string", enum: [tool.name] },
|
|
4983
|
+
// Constrain to this specific tool
|
|
4984
|
+
input: tool.inputSchema
|
|
4985
|
+
// Emitted as-is; the per-provider dialect in llm/schema/compile.ts cleans it now
|
|
4986
|
+
},
|
|
4987
|
+
required: ["type", "id", "name", "input"],
|
|
4988
|
+
additionalProperties: false
|
|
4989
|
+
});
|
|
4990
|
+
}
|
|
4991
|
+
actionSchemas.push({
|
|
4992
|
+
type: "object",
|
|
4993
|
+
properties: {
|
|
4994
|
+
type: { type: "string", enum: ["complete"] }
|
|
4995
|
+
},
|
|
4996
|
+
required: ["type"],
|
|
4997
|
+
additionalProperties: false
|
|
4998
|
+
});
|
|
4999
|
+
const properties = {
|
|
5000
|
+
nextActions: {
|
|
5001
|
+
type: "array",
|
|
5002
|
+
items: {
|
|
5003
|
+
anyOf: actionSchemas
|
|
5004
|
+
}
|
|
5005
|
+
}
|
|
5006
|
+
};
|
|
5007
|
+
if (capabilities.messageAction) {
|
|
5008
|
+
properties.message = {
|
|
5009
|
+
type: "string",
|
|
5010
|
+
description: "Your reply to the user, as plain prose. This is the ONLY field the user sees. Use an empty string only when this iteration just calls tools and you have nothing to say yet."
|
|
5011
|
+
};
|
|
5012
|
+
}
|
|
5013
|
+
properties.reasoning = { type: "string", description: "Your reasoning process" };
|
|
5014
|
+
if (capabilities.memoryOps) {
|
|
5015
|
+
properties.memoryOps = {
|
|
5016
|
+
type: "object",
|
|
5017
|
+
properties: {
|
|
5018
|
+
// Memory keys are dynamic, so the obvious shape is a map with `additionalProperties: true`.
|
|
5019
|
+
// That shape is unrepresentable under strict structured output: it requires
|
|
5020
|
+
// `additionalProperties: false` on every object, which would leave a property-less map
|
|
5021
|
+
// unwritable. Pairs carry the same information and stay inside the grammar. The Zod schema
|
|
5022
|
+
// above accepts the map form too, so nothing already deployed breaks.
|
|
5023
|
+
set: {
|
|
5024
|
+
type: "array",
|
|
5025
|
+
description: "Memory writes, one { key, value } pair per entry.",
|
|
5026
|
+
items: {
|
|
5027
|
+
type: "object",
|
|
5028
|
+
properties: {
|
|
5029
|
+
key: { type: "string" },
|
|
5030
|
+
value: { type: "string" }
|
|
5031
|
+
},
|
|
5032
|
+
required: ["key", "value"],
|
|
5033
|
+
additionalProperties: false
|
|
5034
|
+
}
|
|
5035
|
+
},
|
|
5036
|
+
delete: { type: "array", items: { type: "string" } }
|
|
5037
|
+
},
|
|
5038
|
+
additionalProperties: false
|
|
5039
|
+
};
|
|
5040
|
+
}
|
|
5041
|
+
return {
|
|
5042
|
+
type: "object",
|
|
5043
|
+
properties,
|
|
5044
|
+
required: capabilities.messageAction ? ["nextActions", "message", "reasoning"] : ["nextActions", "reasoning"],
|
|
5045
|
+
additionalProperties: false
|
|
5046
|
+
};
|
|
5047
|
+
}
|
|
5048
|
+
|
|
5049
|
+
// ../core/src/execution/engine/agent/reasoning/adapters/agent-adapter-helpers.ts
|
|
5050
|
+
var MemoryKeyValuePairSchema = z.object({ key: z.string(), value: z.any() });
|
|
5051
|
+
var MemorySetSchema = z.union([z.record(z.string(), z.any()), z.array(MemoryKeyValuePairSchema)]).transform((value) => {
|
|
5052
|
+
if (!Array.isArray(value)) return value;
|
|
5053
|
+
return Object.fromEntries(value.map(({ key, value: v2 }) => [key, v2]));
|
|
5054
|
+
});
|
|
5055
|
+
var MemoryOperationsSchema = z.object({
|
|
5056
|
+
set: MemorySetSchema.optional(),
|
|
5057
|
+
// Accept any value type - framework will stringify
|
|
5058
|
+
delete: z.array(z.string()).optional()
|
|
5059
|
+
});
|
|
5060
|
+
var AgentIterationOutputSchema = z.object({
|
|
5061
|
+
reasoning: z.string(),
|
|
5062
|
+
message: z.string().optional(),
|
|
5063
|
+
memoryOps: MemoryOperationsSchema.optional(),
|
|
5064
|
+
nextActions: z.array(AgentActionSchema)
|
|
5065
|
+
});
|
|
5066
|
+
var REQUIRED_ITERATION_KEYS = Object.entries(AgentIterationOutputSchema.shape).filter(([, fieldSchema]) => !fieldSchema.isOptional()).map(([key]) => key);
|
|
5256
5067
|
function withSynthesizedMessage(nextActions, message) {
|
|
5257
5068
|
const text = message?.trim();
|
|
5258
5069
|
if (!text) {
|
|
@@ -5273,31 +5084,30 @@ async function callLLMForAgentIteration(adapter, request) {
|
|
|
5273
5084
|
request.securityLevel,
|
|
5274
5085
|
request.conversationHistory
|
|
5275
5086
|
);
|
|
5276
|
-
const responseSchema = buildIterationResponseSchema(
|
|
5277
|
-
request.tools,
|
|
5278
|
-
request.includeMessageAction,
|
|
5279
|
-
request.includeNavigateKnowledge,
|
|
5280
|
-
request.includeMemoryOps
|
|
5281
|
-
);
|
|
5087
|
+
const responseSchema = buildIterationResponseSchema(request.tools, request.capabilities);
|
|
5282
5088
|
flowLog("agent.iteration.request", {
|
|
5283
5089
|
model: request.model,
|
|
5284
5090
|
securityLevel: request.securityLevel,
|
|
5285
5091
|
maxOutputTokens: request.constraints.maxOutputTokens,
|
|
5286
5092
|
toolCount: request.tools.length,
|
|
5287
|
-
|
|
5288
|
-
|
|
5093
|
+
messageAction: request.capabilities.messageAction,
|
|
5094
|
+
memoryOps: request.capabilities.memoryOps,
|
|
5289
5095
|
historyTurns: request.conversationHistory?.length ?? 0,
|
|
5290
5096
|
messages: messages.map((m2) => ({ role: m2.role, ...preview(m2.content) }))
|
|
5291
5097
|
});
|
|
5098
|
+
let acceptedOutput;
|
|
5292
5099
|
const response = await adapter.generate({
|
|
5293
5100
|
messages,
|
|
5294
5101
|
responseSchema,
|
|
5295
5102
|
maxOutputTokens: request.constraints.maxOutputTokens,
|
|
5296
5103
|
temperature: request.constraints.temperature,
|
|
5297
|
-
signal: request.signal
|
|
5104
|
+
signal: request.signal,
|
|
5105
|
+
accept: (output) => {
|
|
5106
|
+
acceptedOutput = AgentIterationOutputSchema.parse(output);
|
|
5107
|
+
}
|
|
5298
5108
|
});
|
|
5299
5109
|
try {
|
|
5300
|
-
const validated = AgentIterationOutputSchema.parse(response.output);
|
|
5110
|
+
const validated = acceptedOutput ?? AgentIterationOutputSchema.parse(response.output);
|
|
5301
5111
|
return {
|
|
5302
5112
|
reasoning: validated.reasoning,
|
|
5303
5113
|
memoryOps: validated.memoryOps,
|
|
@@ -5306,14 +5116,15 @@ async function callLLMForAgentIteration(adapter, request) {
|
|
|
5306
5116
|
} catch (error) {
|
|
5307
5117
|
flowLog("agent.iteration.validationFailed", {
|
|
5308
5118
|
returnedKeys: typeof response.output === "object" && response.output !== null ? Object.keys(response.output) : null,
|
|
5309
|
-
missingRequired:
|
|
5119
|
+
missingRequired: REQUIRED_ITERATION_KEYS.filter(
|
|
5310
5120
|
(k2) => !(typeof response.output === "object" && response.output !== null && k2 in response.output)
|
|
5311
5121
|
),
|
|
5312
5122
|
messagePresent: typeof response.output === "object" && response.output !== null && typeof response.output.message === "string",
|
|
5313
5123
|
zodIssues: error instanceof ZodError ? error.issues.map((i) => ({ path: i.path.join("."), code: i.code })) : void 0
|
|
5314
5124
|
});
|
|
5315
|
-
throw new
|
|
5316
|
-
zodError: error instanceof ZodError ? error.format() : error
|
|
5125
|
+
throw new LLMResponseParseError("Agent iteration output validation failed", {
|
|
5126
|
+
zodError: error instanceof ZodError ? error.format() : error,
|
|
5127
|
+
returnedKeys: typeof response.output === "object" && response.output !== null ? Object.keys(response.output) : null
|
|
5317
5128
|
});
|
|
5318
5129
|
}
|
|
5319
5130
|
}
|
|
@@ -5335,119 +5146,6 @@ async function callLLMForAgentCompletion(adapter, request) {
|
|
|
5335
5146
|
});
|
|
5336
5147
|
return response.output;
|
|
5337
5148
|
}
|
|
5338
|
-
function cleanJsonSchemaForLLM(schema) {
|
|
5339
|
-
if (!schema || typeof schema !== "object") {
|
|
5340
|
-
return schema;
|
|
5341
|
-
}
|
|
5342
|
-
const cleaned = {};
|
|
5343
|
-
for (const [key, value] of Object.entries(schema)) {
|
|
5344
|
-
if (key === "$schema") {
|
|
5345
|
-
continue;
|
|
5346
|
-
}
|
|
5347
|
-
if (value && typeof value === "object") {
|
|
5348
|
-
if (Array.isArray(value)) {
|
|
5349
|
-
cleaned[key] = value.map((item) => cleanJsonSchemaForLLM(item));
|
|
5350
|
-
} else {
|
|
5351
|
-
cleaned[key] = cleanJsonSchemaForLLM(value);
|
|
5352
|
-
}
|
|
5353
|
-
} else {
|
|
5354
|
-
cleaned[key] = value;
|
|
5355
|
-
}
|
|
5356
|
-
}
|
|
5357
|
-
if (cleaned.type === "object" && cleaned.properties && typeof cleaned.properties === "object" && Object.keys(cleaned.properties).length === 0) {
|
|
5358
|
-
cleaned.properties.noInputRequired = {
|
|
5359
|
-
type: "boolean",
|
|
5360
|
-
description: "No input required for this tool. Pass true or omit entirely."
|
|
5361
|
-
};
|
|
5362
|
-
}
|
|
5363
|
-
return cleaned;
|
|
5364
|
-
}
|
|
5365
|
-
function buildIterationResponseSchema(tools, includeMessageAction, includeNavigateKnowledge, includeMemoryOps) {
|
|
5366
|
-
const actionSchemas = [];
|
|
5367
|
-
for (const tool of tools) {
|
|
5368
|
-
actionSchemas.push({
|
|
5369
|
-
type: "object",
|
|
5370
|
-
properties: {
|
|
5371
|
-
type: { type: "string", enum: ["tool-call"] },
|
|
5372
|
-
id: { type: "string" },
|
|
5373
|
-
name: { type: "string", enum: [tool.name] },
|
|
5374
|
-
// Constrain to this specific tool
|
|
5375
|
-
input: cleanJsonSchemaForLLM(tool.inputSchema)
|
|
5376
|
-
// Clean and use the actual JSON Schema
|
|
5377
|
-
},
|
|
5378
|
-
required: ["type", "id", "name", "input"],
|
|
5379
|
-
additionalProperties: false
|
|
5380
|
-
});
|
|
5381
|
-
}
|
|
5382
|
-
actionSchemas.push({
|
|
5383
|
-
type: "object",
|
|
5384
|
-
properties: {
|
|
5385
|
-
type: { type: "string", enum: ["complete"] }
|
|
5386
|
-
},
|
|
5387
|
-
required: ["type"],
|
|
5388
|
-
additionalProperties: false
|
|
5389
|
-
});
|
|
5390
|
-
if (includeNavigateKnowledge) {
|
|
5391
|
-
actionSchemas.push({
|
|
5392
|
-
type: "object",
|
|
5393
|
-
properties: {
|
|
5394
|
-
type: { type: "string", enum: ["navigate-knowledge"] },
|
|
5395
|
-
id: { type: "string" },
|
|
5396
|
-
nodeId: { type: "string" }
|
|
5397
|
-
},
|
|
5398
|
-
required: ["type", "id", "nodeId"],
|
|
5399
|
-
additionalProperties: false
|
|
5400
|
-
});
|
|
5401
|
-
}
|
|
5402
|
-
const properties = {
|
|
5403
|
-
nextActions: {
|
|
5404
|
-
type: "array",
|
|
5405
|
-
items: {
|
|
5406
|
-
anyOf: actionSchemas
|
|
5407
|
-
}
|
|
5408
|
-
}
|
|
5409
|
-
};
|
|
5410
|
-
if (includeMessageAction) {
|
|
5411
|
-
properties.message = {
|
|
5412
|
-
type: "string",
|
|
5413
|
-
description: "Your reply to the user, as plain prose. This is the ONLY field the user sees. Use an empty string only when this iteration just calls tools and you have nothing to say yet."
|
|
5414
|
-
};
|
|
5415
|
-
}
|
|
5416
|
-
properties.reasoning = { type: "string", description: "Your reasoning process" };
|
|
5417
|
-
if (includeMemoryOps) {
|
|
5418
|
-
properties.memoryOps = {
|
|
5419
|
-
type: "object",
|
|
5420
|
-
properties: {
|
|
5421
|
-
// Memory keys are dynamic, so the obvious shape is a map with `additionalProperties: true`.
|
|
5422
|
-
// That shape is unrepresentable under strict structured output: it requires
|
|
5423
|
-
// `additionalProperties: false` on every object, which would leave a property-less map
|
|
5424
|
-
// unwritable. Pairs carry the same information and stay inside the grammar. The Zod schema
|
|
5425
|
-
// above accepts the map form too, so nothing already deployed breaks.
|
|
5426
|
-
set: {
|
|
5427
|
-
type: "array",
|
|
5428
|
-
description: "Memory writes, one { key, value } pair per entry.",
|
|
5429
|
-
items: {
|
|
5430
|
-
type: "object",
|
|
5431
|
-
properties: {
|
|
5432
|
-
key: { type: "string" },
|
|
5433
|
-
value: { type: "string" }
|
|
5434
|
-
},
|
|
5435
|
-
required: ["key", "value"],
|
|
5436
|
-
additionalProperties: false
|
|
5437
|
-
}
|
|
5438
|
-
},
|
|
5439
|
-
delete: { type: "array", items: { type: "string" } }
|
|
5440
|
-
},
|
|
5441
|
-
additionalProperties: false
|
|
5442
|
-
};
|
|
5443
|
-
}
|
|
5444
|
-
return {
|
|
5445
|
-
type: "object",
|
|
5446
|
-
properties,
|
|
5447
|
-
required: includeMessageAction ? ["nextActions", "message", "reasoning"] : ["nextActions", "reasoning"],
|
|
5448
|
-
additionalProperties: false
|
|
5449
|
-
};
|
|
5450
|
-
}
|
|
5451
5149
|
|
|
5452
5150
|
// ../core/src/execution/engine/agent/reasoning/processor.ts
|
|
5453
5151
|
async function processReasoning(iterationContext) {
|
|
@@ -5474,9 +5172,7 @@ async function processReasoning(iterationContext) {
|
|
|
5474
5172
|
tools: request.tools,
|
|
5475
5173
|
constraints: request.constraints,
|
|
5476
5174
|
model: iterationContext.modelConfig.model,
|
|
5477
|
-
|
|
5478
|
-
includeNavigateKnowledge: request.includeNavigateKnowledge,
|
|
5479
|
-
includeMemoryOps: request.includeMemoryOps,
|
|
5175
|
+
capabilities: request.capabilities,
|
|
5480
5176
|
signal: iterationContext.executionContext.signal
|
|
5481
5177
|
});
|
|
5482
5178
|
const endTime = Date.now();
|
|
@@ -5529,15 +5225,14 @@ var MEMORY_DOMAINS = {
|
|
|
5529
5225
|
],
|
|
5530
5226
|
/**
|
|
5531
5227
|
* Action-owned keys
|
|
5532
|
-
* Updated by framework actions
|
|
5228
|
+
* Updated by framework actions
|
|
5533
5229
|
* LLM cannot modify these via memoryOps
|
|
5534
5230
|
*
|
|
5535
|
-
* Actions manage framework state that controls execution flow.
|
|
5231
|
+
* Actions manage framework state that controls execution flow. Empty today -- the one
|
|
5232
|
+
* action that ever wrote here was retired. Kept as its own domain because a future
|
|
5233
|
+
* action-managed key belongs here, not folded into TOOL_OWNED.
|
|
5536
5234
|
*/
|
|
5537
|
-
ACTION_OWNED: [
|
|
5538
|
-
"knowledge-map-state"
|
|
5539
|
-
// navigate-knowledge action manages this
|
|
5540
|
-
]
|
|
5235
|
+
ACTION_OWNED: []
|
|
5541
5236
|
/**
|
|
5542
5237
|
* LLM-owned keys
|
|
5543
5238
|
* All keys NOT in TOOL_OWNED or ACTION_OWNED
|
|
@@ -5571,6 +5266,9 @@ function addToolError(memoryManager, action, errorMessage, iteration, turnNumber
|
|
|
5571
5266
|
...metadata?.severity && { severity: metadata.severity },
|
|
5572
5267
|
...metadata?.isRetryable !== void 0 && { isRetryable: metadata.isRetryable }
|
|
5573
5268
|
}),
|
|
5269
|
+
// Mirrors the success path in `executeToolCall`. Without it a failed parallel tool call is
|
|
5270
|
+
// attributable only by parsing `content`, which oversized results can truncate into invalid JSON.
|
|
5271
|
+
toolName: action.name,
|
|
5574
5272
|
turnNumber,
|
|
5575
5273
|
iterationNumber: iteration,
|
|
5576
5274
|
// The envelope is ours; `errorMessage` came out of the tool.
|
|
@@ -5741,6 +5439,7 @@ async function executeToolCall(iterationContext, action) {
|
|
|
5741
5439
|
iterationContext.memoryManager.addToHistory({
|
|
5742
5440
|
type: "tool-result",
|
|
5743
5441
|
content: JSON.stringify(validatedResult),
|
|
5442
|
+
toolName: action.name,
|
|
5744
5443
|
turnNumber: iterationContext.executionContext.sessionTurnNumber ?? null,
|
|
5745
5444
|
iterationNumber: iterationContext.iteration,
|
|
5746
5445
|
source: "tool"
|
|
@@ -5803,189 +5502,7 @@ async function executeToolCall(iterationContext, action) {
|
|
|
5803
5502
|
}
|
|
5804
5503
|
}
|
|
5805
5504
|
|
|
5806
|
-
// ../core/src/execution/engine/agent/actions/navigate-knowledge-executor.ts
|
|
5807
|
-
async function executeNavigateKnowledge(iterationContext, action) {
|
|
5808
|
-
const { knowledgeMap, toolRegistry, memoryManager, executionContext, iteration, logger } = iterationContext;
|
|
5809
|
-
await executionContext.onMessageEvent?.({
|
|
5810
|
-
type: "agent:tool_call",
|
|
5811
|
-
toolName: "navigate_knowledge",
|
|
5812
|
-
args: { nodeId: action.nodeId }
|
|
5813
|
-
});
|
|
5814
|
-
const startTime = Date.now();
|
|
5815
|
-
try {
|
|
5816
|
-
if (!knowledgeMap) {
|
|
5817
|
-
throw new Error("Knowledge map not available - agent does not have knowledge navigation enabled");
|
|
5818
|
-
}
|
|
5819
|
-
const node = knowledgeMap.nodes[action.nodeId];
|
|
5820
|
-
if (!node) {
|
|
5821
|
-
throw new Error(`Knowledge node '${action.nodeId}' not found in knowledge map`);
|
|
5822
|
-
}
|
|
5823
|
-
const content = await node.load(executionContext);
|
|
5824
|
-
node.loaded = true;
|
|
5825
|
-
node.prompt = content.prompt;
|
|
5826
|
-
let childNodesCount = 0;
|
|
5827
|
-
if (content.nodes && Object.keys(content.nodes).length > 0) {
|
|
5828
|
-
for (const [childId, childNode] of Object.entries(content.nodes)) {
|
|
5829
|
-
if (!knowledgeMap.nodes[childId]) {
|
|
5830
|
-
knowledgeMap.nodes[childId] = childNode;
|
|
5831
|
-
childNodesCount++;
|
|
5832
|
-
}
|
|
5833
|
-
}
|
|
5834
|
-
if (childNodesCount > 0) {
|
|
5835
|
-
logger.action(
|
|
5836
|
-
"knowledge-nodes-discovered",
|
|
5837
|
-
`Discovered ${childNodesCount} child nodes from '${action.nodeId}': ${Object.keys(content.nodes).join(", ")}`,
|
|
5838
|
-
iteration,
|
|
5839
|
-
startTime,
|
|
5840
|
-
startTime,
|
|
5841
|
-
0
|
|
5842
|
-
);
|
|
5843
|
-
}
|
|
5844
|
-
}
|
|
5845
|
-
if (content.tools && content.tools.length > 0) {
|
|
5846
|
-
const newTools = [];
|
|
5847
|
-
const skippedTools = [];
|
|
5848
|
-
for (const tool of content.tools) {
|
|
5849
|
-
if (toolRegistry.has(tool.name)) {
|
|
5850
|
-
skippedTools.push(tool.name);
|
|
5851
|
-
} else {
|
|
5852
|
-
toolRegistry.set(tool.name, tool);
|
|
5853
|
-
newTools.push(tool.name);
|
|
5854
|
-
}
|
|
5855
|
-
}
|
|
5856
|
-
if (newTools.length > 0) {
|
|
5857
|
-
logger.action(
|
|
5858
|
-
"knowledge-tools-registered",
|
|
5859
|
-
`Registered ${newTools.length} tools from knowledge node '${action.nodeId}': ${newTools.join(", ")}`,
|
|
5860
|
-
iteration,
|
|
5861
|
-
startTime,
|
|
5862
|
-
startTime,
|
|
5863
|
-
0
|
|
5864
|
-
);
|
|
5865
|
-
}
|
|
5866
|
-
if (skippedTools.length > 0) {
|
|
5867
|
-
logger.action(
|
|
5868
|
-
"knowledge-tools-skipped",
|
|
5869
|
-
`Skipped ${skippedTools.length} already-registered tools: ${skippedTools.join(", ")}`,
|
|
5870
|
-
iteration,
|
|
5871
|
-
startTime,
|
|
5872
|
-
startTime,
|
|
5873
|
-
0
|
|
5874
|
-
);
|
|
5875
|
-
}
|
|
5876
|
-
}
|
|
5877
|
-
const stateKey = "knowledge-map-state";
|
|
5878
|
-
const existingState = memoryManager.get(stateKey);
|
|
5879
|
-
let state;
|
|
5880
|
-
if (existingState) {
|
|
5881
|
-
try {
|
|
5882
|
-
state = JSON.parse(existingState);
|
|
5883
|
-
} catch {
|
|
5884
|
-
state = { loadedNodes: [], version: 1 };
|
|
5885
|
-
}
|
|
5886
|
-
} else {
|
|
5887
|
-
state = { loadedNodes: [], version: 1 };
|
|
5888
|
-
}
|
|
5889
|
-
if (!state.loadedNodes.includes(action.nodeId)) {
|
|
5890
|
-
state.loadedNodes.push(action.nodeId);
|
|
5891
|
-
memoryManager.set(stateKey, JSON.stringify(state));
|
|
5892
|
-
logger.action(
|
|
5893
|
-
"knowledge-state-updated",
|
|
5894
|
-
`Added '${action.nodeId}' to loaded nodes (total: ${state.loadedNodes.length})`,
|
|
5895
|
-
iteration,
|
|
5896
|
-
startTime,
|
|
5897
|
-
startTime,
|
|
5898
|
-
0
|
|
5899
|
-
);
|
|
5900
|
-
}
|
|
5901
|
-
const endTime = Date.now();
|
|
5902
|
-
const duration = endTime - startTime;
|
|
5903
|
-
await executionContext.onMessageEvent?.({
|
|
5904
|
-
type: "agent:tool_result",
|
|
5905
|
-
toolName: "navigate_knowledge",
|
|
5906
|
-
success: true,
|
|
5907
|
-
result: {
|
|
5908
|
-
nodeId: action.nodeId,
|
|
5909
|
-
toolsLoaded: content.tools?.length ?? 0,
|
|
5910
|
-
childNodesDiscovered: childNodesCount,
|
|
5911
|
-
promptLength: content.prompt.length
|
|
5912
|
-
}
|
|
5913
|
-
});
|
|
5914
|
-
logger.toolCall(
|
|
5915
|
-
"navigate_knowledge",
|
|
5916
|
-
iteration,
|
|
5917
|
-
startTime,
|
|
5918
|
-
endTime,
|
|
5919
|
-
duration,
|
|
5920
|
-
true,
|
|
5921
|
-
void 0,
|
|
5922
|
-
{ nodeId: action.nodeId },
|
|
5923
|
-
{
|
|
5924
|
-
nodeId: action.nodeId,
|
|
5925
|
-
toolsLoaded: content.tools?.length ?? 0,
|
|
5926
|
-
childNodesDiscovered: childNodesCount,
|
|
5927
|
-
promptLength: content.prompt.length
|
|
5928
|
-
}
|
|
5929
|
-
);
|
|
5930
|
-
let resultMessage = `Knowledge node '${action.nodeId}' loaded successfully. ${content.tools?.length ?? 0} tools registered.`;
|
|
5931
|
-
if (childNodesCount > 0) {
|
|
5932
|
-
resultMessage += ` ${childNodesCount} child nodes discovered.`;
|
|
5933
|
-
}
|
|
5934
|
-
memoryManager.addToHistory({
|
|
5935
|
-
type: "tool-result",
|
|
5936
|
-
content: resultMessage,
|
|
5937
|
-
turnNumber: executionContext.sessionTurnNumber ?? null,
|
|
5938
|
-
iterationNumber: iteration,
|
|
5939
|
-
// Framework-authored: this string is assembled here from node metadata, not returned by
|
|
5940
|
-
// the node. The node's own prompt text reaches the model through the tool registry.
|
|
5941
|
-
source: "framework"
|
|
5942
|
-
});
|
|
5943
|
-
} catch (error) {
|
|
5944
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5945
|
-
const endTime = Date.now();
|
|
5946
|
-
const duration = endTime - startTime;
|
|
5947
|
-
await executionContext.onMessageEvent?.({
|
|
5948
|
-
type: "agent:tool_result",
|
|
5949
|
-
toolName: "navigate_knowledge",
|
|
5950
|
-
success: false,
|
|
5951
|
-
error: errorMessage
|
|
5952
|
-
});
|
|
5953
|
-
logger.toolCall(
|
|
5954
|
-
"navigate_knowledge",
|
|
5955
|
-
iteration,
|
|
5956
|
-
startTime,
|
|
5957
|
-
endTime,
|
|
5958
|
-
duration,
|
|
5959
|
-
false,
|
|
5960
|
-
errorMessage,
|
|
5961
|
-
{ nodeId: action.nodeId },
|
|
5962
|
-
void 0
|
|
5963
|
-
);
|
|
5964
|
-
memoryManager.addToHistory({
|
|
5965
|
-
type: "error",
|
|
5966
|
-
content: `Error loading knowledge node '${action.nodeId}': ${errorMessage}`,
|
|
5967
|
-
turnNumber: executionContext.sessionTurnNumber ?? null,
|
|
5968
|
-
iterationNumber: iteration,
|
|
5969
|
-
// The wrapper text is ours but `errorMessage` is not — a thrown message can carry
|
|
5970
|
-
// third-party content, so this stays outside the trust boundary.
|
|
5971
|
-
source: "tool"
|
|
5972
|
-
});
|
|
5973
|
-
}
|
|
5974
|
-
}
|
|
5975
|
-
|
|
5976
5505
|
// ../core/src/execution/engine/agent/actions/processor.ts
|
|
5977
|
-
function validateActionSequence(actions) {
|
|
5978
|
-
const completeActions = actions.filter((a3) => a3.type === "complete");
|
|
5979
|
-
if (completeActions.length > 1) {
|
|
5980
|
-
throw new Error("Multiple complete actions not allowed in single iteration");
|
|
5981
|
-
}
|
|
5982
|
-
if (completeActions.length === 1) {
|
|
5983
|
-
const hasNavigateKnowledge = actions.some((a3) => a3.type === "navigate-knowledge");
|
|
5984
|
-
if (hasNavigateKnowledge) {
|
|
5985
|
-
throw new Error("Complete action cannot mix with navigate-knowledge actions");
|
|
5986
|
-
}
|
|
5987
|
-
}
|
|
5988
|
-
}
|
|
5989
5506
|
function normalizeSessionMessages(actions, sessionCapable) {
|
|
5990
5507
|
if (!sessionCapable) {
|
|
5991
5508
|
return actions;
|
|
@@ -6009,9 +5526,8 @@ function normalizeSessionMessages(actions, sessionCapable) {
|
|
|
6009
5526
|
});
|
|
6010
5527
|
}
|
|
6011
5528
|
async function processActions(iterationContext, response) {
|
|
6012
|
-
validateActionSequence(response.nextActions);
|
|
6013
5529
|
const normalizedActions = normalizeSessionMessages(response.nextActions, !!iterationContext.config.sessionCapable);
|
|
6014
|
-
let shouldComplete =
|
|
5530
|
+
let shouldComplete = normalizedActions.some((action) => action.type === "complete");
|
|
6015
5531
|
const toolCalls = [];
|
|
6016
5532
|
const otherActions = [];
|
|
6017
5533
|
for (const action of normalizedActions) {
|
|
@@ -6025,25 +5541,27 @@ async function processActions(iterationContext, response) {
|
|
|
6025
5541
|
await Promise.allSettled(toolCalls.map((action) => executeToolCall(iterationContext, action)));
|
|
6026
5542
|
}
|
|
6027
5543
|
for (const action of otherActions) {
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
shouldComplete = true;
|
|
6034
|
-
break;
|
|
6035
|
-
case "message": {
|
|
6036
|
-
await iterationContext.executionContext.onMessageEvent?.({
|
|
6037
|
-
type: "assistant_message",
|
|
6038
|
-
text: action.text
|
|
6039
|
-
});
|
|
6040
|
-
break;
|
|
6041
|
-
}
|
|
5544
|
+
if (action.type === "message") {
|
|
5545
|
+
await iterationContext.executionContext.onMessageEvent?.({
|
|
5546
|
+
type: "assistant_message",
|
|
5547
|
+
text: action.text
|
|
5548
|
+
});
|
|
6042
5549
|
}
|
|
6043
5550
|
}
|
|
6044
|
-
if (!shouldComplete && iterationContext.config.sessionCapable && toolCalls.length === 0 && normalizedActions.some((a3) => a3.type === "message")
|
|
5551
|
+
if (!shouldComplete && iterationContext.config.sessionCapable && toolCalls.length === 0 && normalizedActions.some((a3) => a3.type === "message")) {
|
|
6045
5552
|
shouldComplete = true;
|
|
6046
5553
|
}
|
|
5554
|
+
flowLog("agent.actions", {
|
|
5555
|
+
iteration: iterationContext.iteration,
|
|
5556
|
+
turnNumber: iterationContext.executionContext.sessionTurnNumber ?? null,
|
|
5557
|
+
actions: normalizedActions.length,
|
|
5558
|
+
types: normalizedActions.map((action) => action.type),
|
|
5559
|
+
toolCalls: toolCalls.map((call2) => call2.name),
|
|
5560
|
+
messages: otherActions.filter((action) => action.type === "message").length,
|
|
5561
|
+
completeRequested: normalizedActions.some((action) => action.type === "complete"),
|
|
5562
|
+
completeInferred: shouldComplete && !normalizedActions.some((action) => action.type === "complete"),
|
|
5563
|
+
shouldComplete
|
|
5564
|
+
});
|
|
6047
5565
|
return { shouldComplete };
|
|
6048
5566
|
}
|
|
6049
5567
|
|
|
@@ -6074,17 +5592,28 @@ async function processMemory(memoryManager, response, logger, iteration) {
|
|
|
6074
5592
|
if (deleted) {
|
|
6075
5593
|
logger.action("memory-delete", `Deleted: ${key}`, iteration, startTime, endTime, endTime - startTime);
|
|
6076
5594
|
} else {
|
|
6077
|
-
logger.action(
|
|
5595
|
+
logger.action(
|
|
5596
|
+
"memory-delete-missing",
|
|
5597
|
+
`Attempted to delete non-existent key: ${key}`,
|
|
5598
|
+
iteration,
|
|
5599
|
+
startTime,
|
|
5600
|
+
endTime,
|
|
5601
|
+
endTime - startTime
|
|
5602
|
+
);
|
|
6078
5603
|
}
|
|
6079
5604
|
}
|
|
6080
5605
|
}
|
|
6081
5606
|
}
|
|
6082
5607
|
|
|
6083
5608
|
// ../core/src/platform/utils/token-counter.ts
|
|
5609
|
+
var CHARS_PER_TOKEN = 3.5;
|
|
6084
5610
|
function estimateTokens(text) {
|
|
6085
5611
|
const content = typeof text === "string" ? text : JSON.stringify(text);
|
|
6086
5612
|
const chars4 = content.length;
|
|
6087
|
-
return Math.ceil(chars4 /
|
|
5613
|
+
return Math.ceil(chars4 / CHARS_PER_TOKEN);
|
|
5614
|
+
}
|
|
5615
|
+
function truncationCharBudget(maxTokens, noticeLength = 0) {
|
|
5616
|
+
return Math.max(0, Math.floor(maxTokens * CHARS_PER_TOKEN) - noticeLength);
|
|
6088
5617
|
}
|
|
6089
5618
|
var UuidSchema = z.string().uuid();
|
|
6090
5619
|
var NonEmptyStringSchema = z.string().trim().min(1).max(1e3);
|
|
@@ -6110,6 +5639,122 @@ z.object({
|
|
|
6110
5639
|
endDate: z.string().datetime()
|
|
6111
5640
|
});
|
|
6112
5641
|
|
|
5642
|
+
// ../core/src/execution/engine/agent/errors.ts
|
|
5643
|
+
var AgentError = class extends ExecutionError {
|
|
5644
|
+
};
|
|
5645
|
+
var AgentInitializationError = class extends AgentError {
|
|
5646
|
+
type = "agent_initialization_error";
|
|
5647
|
+
severity = "critical";
|
|
5648
|
+
category = "agent";
|
|
5649
|
+
constructor(message, context) {
|
|
5650
|
+
super(message, context);
|
|
5651
|
+
}
|
|
5652
|
+
/** Configuration or credential problems. The next attempt fails identically. */
|
|
5653
|
+
isRetryable() {
|
|
5654
|
+
return false;
|
|
5655
|
+
}
|
|
5656
|
+
};
|
|
5657
|
+
var AgentIterationError = class extends AgentError {
|
|
5658
|
+
type = "agent_iteration_error";
|
|
5659
|
+
severity = "warning";
|
|
5660
|
+
category = "agent";
|
|
5661
|
+
constructor(message, context) {
|
|
5662
|
+
super(message, context);
|
|
5663
|
+
}
|
|
5664
|
+
/** The transient case this class exists for -- a bad tool response or a malformed model turn.
|
|
5665
|
+
* The iteration can be re-driven. This is the verdict that was silently `false` while the class
|
|
5666
|
+
* docstring said "may be retried". */
|
|
5667
|
+
isRetryable() {
|
|
5668
|
+
return true;
|
|
5669
|
+
}
|
|
5670
|
+
};
|
|
5671
|
+
var AgentCompletionError = class extends AgentError {
|
|
5672
|
+
type = "agent_completion_error";
|
|
5673
|
+
severity = "warning";
|
|
5674
|
+
category = "agent";
|
|
5675
|
+
constructor(message, context) {
|
|
5676
|
+
super(message, context);
|
|
5677
|
+
}
|
|
5678
|
+
/** Final-output generation is one LLM call; re-driving it is exactly the retry the docstring describes. */
|
|
5679
|
+
isRetryable() {
|
|
5680
|
+
return true;
|
|
5681
|
+
}
|
|
5682
|
+
};
|
|
5683
|
+
var AgentOutputValidationError = class extends AgentError {
|
|
5684
|
+
type = "agent_output_validation_error";
|
|
5685
|
+
severity = "info";
|
|
5686
|
+
category = "validation";
|
|
5687
|
+
constructor(message, context) {
|
|
5688
|
+
super(message, context);
|
|
5689
|
+
}
|
|
5690
|
+
/** The model produced output that does not match the contract, and the same request produces the same
|
|
5691
|
+
* output. `LLMResponseParseError` is the retryable error for "the model can probably do better next
|
|
5692
|
+
* time"; the reasoning adapter throws that for iteration-response parse failures. */
|
|
5693
|
+
isRetryable() {
|
|
5694
|
+
return false;
|
|
5695
|
+
}
|
|
5696
|
+
};
|
|
5697
|
+
var AgentMaxIterationsError = class extends AgentError {
|
|
5698
|
+
type = "agent_max_iterations_error";
|
|
5699
|
+
severity = "critical";
|
|
5700
|
+
category = "agent";
|
|
5701
|
+
constructor(message, context) {
|
|
5702
|
+
super(message, context);
|
|
5703
|
+
}
|
|
5704
|
+
/** The iteration budget is exhausted by definition; retrying re-exhausts it. */
|
|
5705
|
+
isRetryable() {
|
|
5706
|
+
return false;
|
|
5707
|
+
}
|
|
5708
|
+
};
|
|
5709
|
+
var AgentTimeoutError = class extends AgentError {
|
|
5710
|
+
type = "agent_timeout_error";
|
|
5711
|
+
severity = "critical";
|
|
5712
|
+
category = "agent";
|
|
5713
|
+
constructor(message, context) {
|
|
5714
|
+
super(message, context);
|
|
5715
|
+
}
|
|
5716
|
+
/** The execution ceiling was reached, so a retry has no budget to run in. */
|
|
5717
|
+
isRetryable() {
|
|
5718
|
+
return false;
|
|
5719
|
+
}
|
|
5720
|
+
};
|
|
5721
|
+
var AgentCancellationError = class extends AgentError {
|
|
5722
|
+
type = "agent_cancellation_error";
|
|
5723
|
+
severity = "warning";
|
|
5724
|
+
category = "agent";
|
|
5725
|
+
constructor(message, context) {
|
|
5726
|
+
super(message, context);
|
|
5727
|
+
}
|
|
5728
|
+
/** The user asked for this. Retrying would override an explicit instruction. */
|
|
5729
|
+
isRetryable() {
|
|
5730
|
+
return false;
|
|
5731
|
+
}
|
|
5732
|
+
};
|
|
5733
|
+
var AgentStalledError = class extends AgentError {
|
|
5734
|
+
type = "agent_stalled_error";
|
|
5735
|
+
severity = "critical";
|
|
5736
|
+
category = "agent";
|
|
5737
|
+
constructor(message, context) {
|
|
5738
|
+
super(message, context);
|
|
5739
|
+
}
|
|
5740
|
+
/** Terminalized out of band by the heartbeat monitor; the process that would retry is the one declared dead. */
|
|
5741
|
+
isRetryable() {
|
|
5742
|
+
return false;
|
|
5743
|
+
}
|
|
5744
|
+
};
|
|
5745
|
+
var AgentMemoryValidationError = class extends AgentError {
|
|
5746
|
+
type = "agent_memory_validation_error";
|
|
5747
|
+
severity = "info";
|
|
5748
|
+
category = "validation";
|
|
5749
|
+
constructor(message, context) {
|
|
5750
|
+
super(message, context);
|
|
5751
|
+
}
|
|
5752
|
+
/** A malformed memory entry is a caller bug, not a transient condition. */
|
|
5753
|
+
isRetryable() {
|
|
5754
|
+
return false;
|
|
5755
|
+
}
|
|
5756
|
+
};
|
|
5757
|
+
|
|
6113
5758
|
// ../core/src/platform/constants/limits.ts
|
|
6114
5759
|
var MAX_SESSION_MEMORY_KEYS = 25;
|
|
6115
5760
|
var MAX_MEMORY_TOKENS = 32e3;
|
|
@@ -6118,16 +5763,17 @@ var MAX_SINGLE_ENTRY_TOKENS = 2e3;
|
|
|
6118
5763
|
var MAX_TOOL_RESULT_TOKENS = 4e3;
|
|
6119
5764
|
|
|
6120
5765
|
// ../core/src/execution/engine/agent/memory/manager.ts
|
|
6121
|
-
var CHARS_PER_TOKEN = 3.5;
|
|
6122
5766
|
function truncateToolResult(content, maxTokens) {
|
|
6123
5767
|
const estimated = estimateTokens(content);
|
|
6124
5768
|
if (estimated <= maxTokens) return content;
|
|
6125
|
-
const maxChars = Math.floor(maxTokens * 3.5);
|
|
6126
|
-
const truncated = content.slice(0, maxChars);
|
|
6127
5769
|
const omitted = estimated - maxTokens;
|
|
6128
|
-
|
|
5770
|
+
const notice = `
|
|
6129
5771
|
|
|
6130
5772
|
[Response truncated \u2014 estimated ${omitted} tokens omitted. Use more specific filters to get smaller results.]`;
|
|
5773
|
+
return content.slice(0, truncationCharBudget(maxTokens, notice.length)) + notice;
|
|
5774
|
+
}
|
|
5775
|
+
function isInTurnScope(entry, currentTurn) {
|
|
5776
|
+
return !currentTurn || entry.turnNumber === currentTurn || entry.turnNumber == null;
|
|
6131
5777
|
}
|
|
6132
5778
|
function keepAnchored(history, recent) {
|
|
6133
5779
|
if (history.length <= recent + 1) return history;
|
|
@@ -6159,8 +5805,7 @@ var MemoryManager = class {
|
|
|
6159
5805
|
0
|
|
6160
5806
|
);
|
|
6161
5807
|
const notice = "... [truncated]";
|
|
6162
|
-
|
|
6163
|
-
content = content.slice(0, maxChars) + notice;
|
|
5808
|
+
content = content.slice(0, truncationCharBudget(MAX_SINGLE_ENTRY_TOKENS, notice.length)) + notice;
|
|
6164
5809
|
}
|
|
6165
5810
|
this.memory.sessionMemory[key] = {
|
|
6166
5811
|
type: "context",
|
|
@@ -6209,14 +5854,14 @@ var MemoryManager = class {
|
|
|
6209
5854
|
});
|
|
6210
5855
|
}
|
|
6211
5856
|
let content = entry.content;
|
|
6212
|
-
if (entry.type === "tool-result") {
|
|
5857
|
+
if (entry.type === "tool-result" || entry.type === "error") {
|
|
6213
5858
|
const before = content;
|
|
6214
5859
|
content = truncateToolResult(content, MAX_TOOL_RESULT_TOKENS);
|
|
6215
5860
|
if (content !== before) {
|
|
6216
5861
|
const truncateTime = Date.now();
|
|
6217
5862
|
this.logger?.action(
|
|
6218
5863
|
"memory-tool-result-truncate",
|
|
6219
|
-
|
|
5864
|
+
`${entry.type === "error" ? "Tool error" : "Tool result"} truncated (${estimateTokens(before)} -> ${MAX_TOOL_RESULT_TOKENS} tokens)`,
|
|
6220
5865
|
entry.iterationNumber ?? 0,
|
|
6221
5866
|
truncateTime,
|
|
6222
5867
|
truncateTime,
|
|
@@ -6237,7 +5882,7 @@ var MemoryManager = class {
|
|
|
6237
5882
|
*/
|
|
6238
5883
|
autoCompact() {
|
|
6239
5884
|
const status = this.getStatus();
|
|
6240
|
-
if (status.
|
|
5885
|
+
if (status.storedHistoryPercent >= 100) {
|
|
6241
5886
|
const before = this.memory.history.length;
|
|
6242
5887
|
this.memory.history = keepAnchored(this.memory.history, 10);
|
|
6243
5888
|
const compactTime = Date.now();
|
|
@@ -6273,12 +5918,12 @@ var MemoryManager = class {
|
|
|
6273
5918
|
}
|
|
6274
5919
|
this.enforceSessionMemoryTokenLimit();
|
|
6275
5920
|
const status = this.getStatus();
|
|
6276
|
-
if (status.
|
|
5921
|
+
if (status.storedHistoryTokens > status.historyBudget) {
|
|
6277
5922
|
const before = this.memory.history.length;
|
|
6278
5923
|
const emergencyStartTime = Date.now();
|
|
6279
5924
|
this.logger?.action(
|
|
6280
5925
|
"memory-emergency",
|
|
6281
|
-
`History exceeds its token budget (${status.
|
|
5926
|
+
`History exceeds its token budget (${status.storedHistoryTokens}/${status.historyBudget}), forcing emergency compaction`,
|
|
6282
5927
|
0,
|
|
6283
5928
|
emergencyStartTime,
|
|
6284
5929
|
emergencyStartTime,
|
|
@@ -6303,17 +5948,24 @@ var MemoryManager = class {
|
|
|
6303
5948
|
* are not. Eviction is oldest-first by timestamp, matching the key-count path, and always
|
|
6304
5949
|
* leaves at least one entry so a single oversized key degrades to "one key" rather than to
|
|
6305
5950
|
* "memory silently emptied".
|
|
5951
|
+
*
|
|
5952
|
+
* The running total is **recomputed** from the survivors rather than decremented per entry.
|
|
5953
|
+
* `getStatus` estimates the pool as a ceiling of the joined sum, and a per-entry decrement is a
|
|
5954
|
+
* sum of ceilings — the larger of the two by up to one token per key. The running total therefore
|
|
5955
|
+
* fell faster than the pool did, and the loop could exit reporting a fit while the very next
|
|
5956
|
+
* `getStatus` still read over the limit. Recomputing makes the loop's exit condition and the
|
|
5957
|
+
* number it is judged by the same expression. The pool is capped at `MAX_SESSION_MEMORY_KEYS`
|
|
5958
|
+
* entries, so the extra passes are bounded and cheap.
|
|
6306
5959
|
*/
|
|
6307
5960
|
enforceSessionMemoryTokenLimit() {
|
|
6308
5961
|
const { sessionMemoryTokens, sessionMemoryTokenLimit } = this.getStatus();
|
|
6309
5962
|
if (sessionMemoryTokens <= sessionMemoryTokenLimit) return;
|
|
6310
5963
|
const sorted = Object.entries(this.memory.sessionMemory).sort((a3, b2) => a3[1].timestamp - b2[1].timestamp);
|
|
6311
5964
|
const startTime = Date.now();
|
|
6312
|
-
|
|
5965
|
+
const poolTokens = () => estimateTokens(sorted.map(([, entry]) => entry.content).join(""));
|
|
6313
5966
|
let dropped = 0;
|
|
6314
|
-
while (
|
|
6315
|
-
|
|
6316
|
-
running -= estimateTokens(evicted.content);
|
|
5967
|
+
while (poolTokens() > sessionMemoryTokenLimit && sorted.length > 1) {
|
|
5968
|
+
sorted.shift();
|
|
6317
5969
|
dropped++;
|
|
6318
5970
|
}
|
|
6319
5971
|
this.memory.sessionMemory = Object.fromEntries(sorted);
|
|
@@ -6336,14 +5988,21 @@ var MemoryManager = class {
|
|
|
6336
5988
|
}
|
|
6337
5989
|
/**
|
|
6338
5990
|
* Get memory status for agent awareness
|
|
5991
|
+
*
|
|
5992
|
+
* @param currentTurn - Turn to scope `historyTokens` / `historyPercent` to. Omit to measure the
|
|
5993
|
+
* whole store, which is what the compaction paths want. Callers building something the model
|
|
5994
|
+
* reads should pass it, so the count describes the set the model is actually handed.
|
|
6339
5995
|
* @returns Memory status with token usage and key counts
|
|
6340
5996
|
*/
|
|
6341
|
-
getStatus() {
|
|
5997
|
+
getStatus(currentTurn) {
|
|
6342
5998
|
const sessionMemoryKeys = Object.keys(this.memory.sessionMemory);
|
|
6343
5999
|
const sessionMemoryContent = Object.values(this.memory.sessionMemory).map((entry) => entry.content).join("");
|
|
6344
|
-
const historyContent = this.memory.history.map((entry) => entry.content).join("");
|
|
6345
6000
|
const sessionMemoryTokens = estimateTokens(sessionMemoryContent);
|
|
6346
|
-
const
|
|
6001
|
+
const storedContent = this.memory.history.map((entry) => entry.content).join("");
|
|
6002
|
+
const storedHistoryTokens = estimateTokens(storedContent);
|
|
6003
|
+
const historyTokens = currentTurn === void 0 ? storedHistoryTokens : estimateTokens(
|
|
6004
|
+
this.memory.history.filter((entry) => isInTurnScope(entry, currentTurn)).map((entry) => entry.content).join("")
|
|
6005
|
+
);
|
|
6347
6006
|
const tokenBudget = this.constraints.maxMemoryTokens || MAX_MEMORY_TOKENS;
|
|
6348
6007
|
const sessionMemoryTokenLimit = Math.min(MAX_SESSION_MEMORY_TOKENS, Math.floor(tokenBudget * 0.25));
|
|
6349
6008
|
const historyBudget = Math.max(tokenBudget - sessionMemoryTokenLimit, 1);
|
|
@@ -6351,14 +6010,13 @@ var MemoryManager = class {
|
|
|
6351
6010
|
return {
|
|
6352
6011
|
sessionMemoryKeys: sessionMemoryKeys.length,
|
|
6353
6012
|
sessionMemoryLimit,
|
|
6354
|
-
currentKeys: sessionMemoryKeys,
|
|
6355
6013
|
sessionMemoryTokens,
|
|
6356
6014
|
sessionMemoryTokenLimit,
|
|
6357
6015
|
historyPercent: Math.round(historyTokens / historyBudget * 100),
|
|
6358
6016
|
historyTokens,
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6017
|
+
storedHistoryTokens,
|
|
6018
|
+
storedHistoryPercent: Math.round(storedHistoryTokens / historyBudget * 100),
|
|
6019
|
+
historyBudget
|
|
6362
6020
|
};
|
|
6363
6021
|
}
|
|
6364
6022
|
/**
|
|
@@ -6402,8 +6060,8 @@ var MemoryManager = class {
|
|
|
6402
6060
|
* @param currentTurn - Current turn number (optional, for session context filtering)
|
|
6403
6061
|
*/
|
|
6404
6062
|
toContextParts(currentIteration, currentTurn) {
|
|
6405
|
-
const status = this.getStatus();
|
|
6406
|
-
const inTurnScope = (entry) =>
|
|
6063
|
+
const status = this.getStatus(currentTurn);
|
|
6064
|
+
const inTurnScope = (entry) => isInTurnScope(entry, currentTurn);
|
|
6407
6065
|
const isCurrentInput = (entry) => entry.type === "input" && entry.iterationNumber === 0;
|
|
6408
6066
|
const currentContext = this.memory.history.filter((entry) => inTurnScope(entry) && !isCurrentInput(entry) && entry.iterationNumber === currentIteration).reverse();
|
|
6409
6067
|
const earlierContext = this.memory.history.filter(
|
|
@@ -6416,8 +6074,7 @@ var MemoryManager = class {
|
|
|
6416
6074
|
// or came from a stale bundle, and calling that framework-authored would be a lie in the
|
|
6417
6075
|
// one direction that matters.
|
|
6418
6076
|
source: entry.source ?? "unknown",
|
|
6419
|
-
|
|
6420
|
-
iteration: entry.iterationNumber,
|
|
6077
|
+
...entry.toolName !== void 0 && { toolName: entry.toolName },
|
|
6421
6078
|
...key !== void 0 && { key },
|
|
6422
6079
|
content: entry.content
|
|
6423
6080
|
});
|
|
@@ -6426,15 +6083,15 @@ var MemoryManager = class {
|
|
|
6426
6083
|
...currentContext.map((entry) => fragment("current-iteration", entry)),
|
|
6427
6084
|
...earlierContext.map((entry) => fragment("earlier", entry))
|
|
6428
6085
|
];
|
|
6086
|
+
const persistNudge = status.storedHistoryPercent >= 80 ? "Memory is filling up -- persist anything you still need now; the framework auto-compacts soon." : "";
|
|
6429
6087
|
const framing = `
|
|
6430
6088
|
=== MEMORY STATUS ===
|
|
6431
|
-
${
|
|
6432
|
-
Session memory: ${status.sessionMemoryTokens}/${status.sessionMemoryTokenLimit} tokens
|
|
6433
|
-
History: ${status.historyTokens}/${status.historyBudget} tokens (${status.historyPercent}% of budget)
|
|
6089
|
+
${persistNudge}
|
|
6434
6090
|
|
|
6435
6091
|
=== HOW TO READ THIS TURN ===
|
|
6436
6092
|
The next message lists your stored content under "untrustedData". Each entry records where a
|
|
6437
|
-
fragment came from ("slot", "source"
|
|
6093
|
+
fragment came from ("slot", "source") and what it said ("content"); tool results also carry
|
|
6094
|
+
"toolName" so parallel results stay attributable.
|
|
6438
6095
|
- slot "session-memory" persists across turns; "current-iteration" is iteration ${currentIteration}'s
|
|
6439
6096
|
own work, most recent first; "earlier" is prior iterations of this turn, chronological.
|
|
6440
6097
|
- source records who wrote it: "user", "tool", "model", or "unknown".
|
|
@@ -6462,64 +6119,12 @@ This is input only. Your own reply is captured as structured output and never lo
|
|
|
6462
6119
|
return { framing, dataEnvelope };
|
|
6463
6120
|
}
|
|
6464
6121
|
};
|
|
6465
|
-
|
|
6466
|
-
// ../core/src/execution/engine/agent/knowledge-map/utils.ts
|
|
6467
|
-
async function reloadKnowledgeMapTools(knowledgeMap, memory, context) {
|
|
6468
|
-
const stateJson = memory.sessionMemory["knowledge-map-state"];
|
|
6469
|
-
if (!stateJson) {
|
|
6470
|
-
return [];
|
|
6471
|
-
}
|
|
6472
|
-
try {
|
|
6473
|
-
const state = JSON.parse(stateJson.content);
|
|
6474
|
-
const tools = [];
|
|
6475
|
-
for (const nodeId of state.loadedNodes) {
|
|
6476
|
-
const node = knowledgeMap.nodes[nodeId];
|
|
6477
|
-
if (!node) {
|
|
6478
|
-
context.logger.warn(`Knowledge node '${nodeId}' not found during reload (skipping)`);
|
|
6479
|
-
continue;
|
|
6480
|
-
}
|
|
6481
|
-
try {
|
|
6482
|
-
const content = await node.load(context);
|
|
6483
|
-
node.loaded = true;
|
|
6484
|
-
node.prompt = content.prompt;
|
|
6485
|
-
if (content.nodes && Object.keys(content.nodes).length > 0) {
|
|
6486
|
-
for (const [childId, childNode] of Object.entries(content.nodes)) {
|
|
6487
|
-
if (!knowledgeMap.nodes[childId]) {
|
|
6488
|
-
knowledgeMap.nodes[childId] = childNode;
|
|
6489
|
-
}
|
|
6490
|
-
}
|
|
6491
|
-
}
|
|
6492
|
-
if (content.tools && content.tools.length > 0) {
|
|
6493
|
-
tools.push(...content.tools);
|
|
6494
|
-
}
|
|
6495
|
-
} catch (error) {
|
|
6496
|
-
const errorMessage = errorToString(error);
|
|
6497
|
-
context.logger.error(`Failed to reload knowledge node '${nodeId}': ${errorMessage}`);
|
|
6498
|
-
}
|
|
6499
|
-
}
|
|
6500
|
-
return tools;
|
|
6501
|
-
} catch (error) {
|
|
6502
|
-
const errorMessage = errorToString(error);
|
|
6503
|
-
context.logger.error(`Failed to parse knowledge-map-state: ${errorMessage}`);
|
|
6504
|
-
return [];
|
|
6505
|
-
}
|
|
6506
|
-
}
|
|
6507
|
-
function initializeKnowledgeMap(knowledgeMap) {
|
|
6508
|
-
if (!knowledgeMap) return void 0;
|
|
6509
|
-
return {
|
|
6510
|
-
nodes: Object.fromEntries(Object.entries(knowledgeMap.nodes).map(([id, node]) => [id, { ...node }]))
|
|
6511
|
-
};
|
|
6512
|
-
}
|
|
6513
|
-
function hasMemoryContent(memory) {
|
|
6514
|
-
return Object.keys(memory.sessionMemory).length > 0 || memory.history.length > 0;
|
|
6515
|
-
}
|
|
6516
6122
|
var Agent = class {
|
|
6517
6123
|
// Base properties from definition
|
|
6518
6124
|
config;
|
|
6519
6125
|
contract;
|
|
6520
6126
|
toolRegistry;
|
|
6521
6127
|
modelConfig;
|
|
6522
|
-
knowledgeMap;
|
|
6523
6128
|
definition;
|
|
6524
6129
|
adapterFactory;
|
|
6525
6130
|
initialMemory;
|
|
@@ -6551,7 +6156,6 @@ var Agent = class {
|
|
|
6551
6156
|
this.config = definition.config;
|
|
6552
6157
|
this.contract = definition.contract;
|
|
6553
6158
|
this.modelConfig = definition.modelConfig;
|
|
6554
|
-
this.knowledgeMap = initializeKnowledgeMap(definition.knowledgeMap);
|
|
6555
6159
|
this.toolRegistry = /* @__PURE__ */ new Map();
|
|
6556
6160
|
for (const tool of definition.tools) {
|
|
6557
6161
|
this.toolRegistry.set(tool.name, tool);
|
|
@@ -6581,8 +6185,7 @@ var Agent = class {
|
|
|
6581
6185
|
}
|
|
6582
6186
|
}
|
|
6583
6187
|
/**
|
|
6584
|
-
* Register tools
|
|
6585
|
-
* Called by navigate_knowledge tool during execution
|
|
6188
|
+
* Register additional tools at runtime
|
|
6586
6189
|
*
|
|
6587
6190
|
* @param tools - Array of tools to register
|
|
6588
6191
|
* Note: Silently skips tools that are already registered
|
|
@@ -6633,9 +6236,6 @@ var Agent = class {
|
|
|
6633
6236
|
* Initialize memory manager with preloaded memory and input entry
|
|
6634
6237
|
* Encapsulates all memory initialization complexity
|
|
6635
6238
|
*
|
|
6636
|
-
* Also handles cross-turn persistence: re-registers tools from knowledge nodes
|
|
6637
|
-
* that were loaded in previous session turns.
|
|
6638
|
-
*
|
|
6639
6239
|
* Reads `this.currentInput`, which `initialize` serializes from the validated input.
|
|
6640
6240
|
*
|
|
6641
6241
|
* @param context - Execution context (passed to preloadMemory)
|
|
@@ -6643,9 +6243,6 @@ var Agent = class {
|
|
|
6643
6243
|
*/
|
|
6644
6244
|
async initializeMemoryManager(context) {
|
|
6645
6245
|
const memory = await this.resolveInitialMemory(context);
|
|
6646
|
-
if (hasMemoryContent(memory)) {
|
|
6647
|
-
await this.reloadKnowledgeMapTools(memory, context);
|
|
6648
|
-
}
|
|
6649
6246
|
const inputStartTime = Date.now();
|
|
6650
6247
|
memory.history.push({
|
|
6651
6248
|
type: "input",
|
|
@@ -6713,71 +6310,6 @@ var Agent = class {
|
|
|
6713
6310
|
}
|
|
6714
6311
|
return { sessionMemory: {}, history: [] };
|
|
6715
6312
|
}
|
|
6716
|
-
/**
|
|
6717
|
-
* Reload tools from knowledge map state (cross-turn persistence)
|
|
6718
|
-
*
|
|
6719
|
-
* Reads the knowledge-map-state from sessionMemory and re-registers
|
|
6720
|
-
* tools from previously loaded knowledge nodes.
|
|
6721
|
-
*
|
|
6722
|
-
* @param memory - Agent memory with sessionMemory state
|
|
6723
|
-
* @param context - Execution context
|
|
6724
|
-
*/
|
|
6725
|
-
async reloadKnowledgeMapTools(memory, context) {
|
|
6726
|
-
if (!this.knowledgeMap) {
|
|
6727
|
-
return;
|
|
6728
|
-
}
|
|
6729
|
-
const stateJson = memory.sessionMemory["knowledge-map-state"];
|
|
6730
|
-
if (!stateJson) {
|
|
6731
|
-
return;
|
|
6732
|
-
}
|
|
6733
|
-
const reloadStartTime = Date.now();
|
|
6734
|
-
try {
|
|
6735
|
-
const tools = await reloadKnowledgeMapTools(this.knowledgeMap, memory, context);
|
|
6736
|
-
let registeredCount = 0;
|
|
6737
|
-
let skippedCount = 0;
|
|
6738
|
-
for (const tool of tools) {
|
|
6739
|
-
if (this.toolRegistry.has(tool.name)) {
|
|
6740
|
-
skippedCount++;
|
|
6741
|
-
} else {
|
|
6742
|
-
this.toolRegistry.set(tool.name, tool);
|
|
6743
|
-
registeredCount++;
|
|
6744
|
-
}
|
|
6745
|
-
}
|
|
6746
|
-
const reloadEndTime = Date.now();
|
|
6747
|
-
if (registeredCount > 0) {
|
|
6748
|
-
const state = JSON.parse(stateJson.content);
|
|
6749
|
-
this.logger.action(
|
|
6750
|
-
"knowledge-reload",
|
|
6751
|
-
`Reloaded ${registeredCount} tools from ${state.loadedNodes.length} knowledge nodes: ${state.loadedNodes.join(", ")}`,
|
|
6752
|
-
0,
|
|
6753
|
-
reloadStartTime,
|
|
6754
|
-
reloadEndTime,
|
|
6755
|
-
reloadEndTime - reloadStartTime
|
|
6756
|
-
);
|
|
6757
|
-
}
|
|
6758
|
-
if (skippedCount > 0) {
|
|
6759
|
-
this.logger.action(
|
|
6760
|
-
"knowledge-reload-skipped",
|
|
6761
|
-
`Skipped ${skippedCount} already-registered tools during reload`,
|
|
6762
|
-
0,
|
|
6763
|
-
reloadStartTime,
|
|
6764
|
-
reloadEndTime,
|
|
6765
|
-
reloadEndTime - reloadStartTime
|
|
6766
|
-
);
|
|
6767
|
-
}
|
|
6768
|
-
} catch (error) {
|
|
6769
|
-
const errorMessage = errorToString(error);
|
|
6770
|
-
const reloadEndTime = Date.now();
|
|
6771
|
-
this.logger.action(
|
|
6772
|
-
"knowledge-reload-failed",
|
|
6773
|
-
`Failed to reload knowledge map: ${errorMessage}`,
|
|
6774
|
-
0,
|
|
6775
|
-
reloadStartTime,
|
|
6776
|
-
reloadEndTime,
|
|
6777
|
-
reloadEndTime - reloadStartTime
|
|
6778
|
-
);
|
|
6779
|
-
}
|
|
6780
|
-
}
|
|
6781
6313
|
/**
|
|
6782
6314
|
* Phase 2: Run the agent iteration loop
|
|
6783
6315
|
* Continues until LLM signals completion or max iterations reached
|
|
@@ -6927,7 +6459,7 @@ var Agent = class {
|
|
|
6927
6459
|
});
|
|
6928
6460
|
const modelTemperature = this.modelConfig.temperature ?? 0.7;
|
|
6929
6461
|
const initialOutput = await this.callLLMForOutput(
|
|
6930
|
-
this.buildOutputGenerationPrompt(),
|
|
6462
|
+
this.buildOutputGenerationPrompt(outputSchema),
|
|
6931
6463
|
outputSchema,
|
|
6932
6464
|
modelTemperature,
|
|
6933
6465
|
"output-generation"
|
|
@@ -6945,7 +6477,7 @@ var Agent = class {
|
|
|
6945
6477
|
validationTime,
|
|
6946
6478
|
0
|
|
6947
6479
|
);
|
|
6948
|
-
const retryPrompt = this.buildRetryPrompt(initialOutput, initialResult.error);
|
|
6480
|
+
const retryPrompt = this.buildRetryPrompt(outputSchema, initialOutput, initialResult.error);
|
|
6949
6481
|
const retryOutput = await this.callLLMForOutput(
|
|
6950
6482
|
retryPrompt,
|
|
6951
6483
|
outputSchema,
|
|
@@ -7035,14 +6567,13 @@ var Agent = class {
|
|
|
7035
6567
|
* Instructs LLM to synthesize execution history into structured output
|
|
7036
6568
|
* Note: Only called from generateFinalOutput() which ensures outputSchema exists
|
|
7037
6569
|
*
|
|
6570
|
+
* @param schemaJson - The output schema, already converted once by the caller. Retrying a
|
|
6571
|
+
* failed attempt calls this a second time for the SAME schema, so the conversion itself is the
|
|
6572
|
+
* caller's job -- `generateFinalOutput` converts `contract.outputSchema` exactly once per
|
|
6573
|
+
* completion call, not once per prompt built from it.
|
|
7038
6574
|
* @returns System prompt for completion phase
|
|
7039
6575
|
*/
|
|
7040
|
-
buildOutputGenerationPrompt() {
|
|
7041
|
-
const schema = this.contract.outputSchema;
|
|
7042
|
-
const schemaJson = zodToJsonSchema(schema, {
|
|
7043
|
-
$refStrategy: "none",
|
|
7044
|
-
errorMessages: true
|
|
7045
|
-
});
|
|
6576
|
+
buildOutputGenerationPrompt(schemaJson) {
|
|
7046
6577
|
return `
|
|
7047
6578
|
You have completed a task. Generate the final output based on the execution history.
|
|
7048
6579
|
|
|
@@ -7069,13 +6600,15 @@ Generate the final output now.
|
|
|
7069
6600
|
/**
|
|
7070
6601
|
* Build retry prompt with validation error context
|
|
7071
6602
|
*
|
|
6603
|
+
* @param schemaJson - The output schema, forwarded to `buildOutputGenerationPrompt` rather than
|
|
6604
|
+
* reconverted here
|
|
7072
6605
|
* @param failedOutput - The output that failed validation
|
|
7073
6606
|
* @param validationError - Zod validation error with details
|
|
7074
6607
|
* @returns System prompt for retry attempt
|
|
7075
6608
|
*/
|
|
7076
|
-
buildRetryPrompt(failedOutput, validationError) {
|
|
6609
|
+
buildRetryPrompt(schemaJson, failedOutput, validationError) {
|
|
7077
6610
|
return `
|
|
7078
|
-
${this.buildOutputGenerationPrompt()}
|
|
6611
|
+
${this.buildOutputGenerationPrompt(schemaJson)}
|
|
7079
6612
|
|
|
7080
6613
|
## Previous Attempt (FAILED VALIDATION)
|
|
7081
6614
|
|
|
@@ -7113,8 +6646,7 @@ Fix the errors and generate a valid output.
|
|
|
7113
6646
|
logger: this.logger,
|
|
7114
6647
|
modelConfig: this.modelConfig,
|
|
7115
6648
|
adapterFactory: this.adapterFactory,
|
|
7116
|
-
currentInput: this.currentInput
|
|
7117
|
-
knowledgeMap: this.knowledgeMap
|
|
6649
|
+
currentInput: this.currentInput
|
|
7118
6650
|
};
|
|
7119
6651
|
}
|
|
7120
6652
|
/**
|
|
@@ -8451,6 +7983,10 @@ var PostMessageLLMAdapter = class {
|
|
|
8451
7983
|
model: this.model,
|
|
8452
7984
|
messages: request.messages,
|
|
8453
7985
|
responseSchema: request.responseSchema,
|
|
7986
|
+
// Plain data, so unlike `accept` (a function, dropped by this allowlist because it cannot be
|
|
7987
|
+
// structured-cloned) it survives postMessage. The parent-side `case 'llm'` branch in
|
|
7988
|
+
// `tool-dispatcher.ts` puts it back on the LLMGenerateRequest it rebuilds.
|
|
7989
|
+
validationSchema: request.validationSchema,
|
|
8454
7990
|
temperature: request.temperature,
|
|
8455
7991
|
maxOutputTokens: request.maxOutputTokens
|
|
8456
7992
|
}
|