@axiom-lattice/core 3.0.4 → 3.0.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/index.d.mts +35 -6
- package/dist/index.d.ts +35 -6
- package/dist/index.js +614 -316
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +482 -185
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -9394,8 +9394,11 @@ Please select a valid tool from the list above.`
|
|
|
9394
9394
|
* The only place to access request.tools (all available tools).
|
|
9395
9395
|
* Identifies unknown tools and stores error info in metadata.
|
|
9396
9396
|
*
|
|
9397
|
-
* Key:
|
|
9398
|
-
*
|
|
9397
|
+
* Key: Strip valid tool_calls and only keep unknown ones in the returned
|
|
9398
|
+
* AIMessage. Valid calls must NOT be preserved: afterModel jumps to "model"
|
|
9399
|
+
* and skips ToolNode, so a preserved valid call would have no ToolMessage
|
|
9400
|
+
* and the next model call would be rejected with a 400 dangling tool_calls
|
|
9401
|
+
* error. Stripped valid calls are re-issued by the model in the next round.
|
|
9399
9402
|
*/
|
|
9400
9403
|
wrapModelCall: async (request, handler) => {
|
|
9401
9404
|
const availableTools = request.tools || [];
|
|
@@ -9425,10 +9428,11 @@ Please select a valid tool from the list above.`
|
|
|
9425
9428
|
toolCallId: toolCall.id,
|
|
9426
9429
|
errorMessage: errorMessageTemplate(toolCall.name, availableToolNames)
|
|
9427
9430
|
}));
|
|
9431
|
+
const unknownToolIds = new Set(unknownToolCalls.map((toolCall) => toolCall.id));
|
|
9432
|
+
const remainingToolCalls = aiResponse.tool_calls.filter((toolCall) => unknownToolIds.has(toolCall.id));
|
|
9428
9433
|
const modifiedResponse = new AIMessage({
|
|
9429
9434
|
content: aiResponse.content,
|
|
9430
|
-
tool_calls:
|
|
9431
|
-
// Key: preserve all tool_calls, don't delete unknown
|
|
9435
|
+
tool_calls: remainingToolCalls,
|
|
9432
9436
|
response_metadata: {
|
|
9433
9437
|
...aiResponse.response_metadata,
|
|
9434
9438
|
_unknownToolErrors: unknownToolErrors
|
|
@@ -9481,6 +9485,68 @@ Please select a valid tool from the list above.`
|
|
|
9481
9485
|
});
|
|
9482
9486
|
}
|
|
9483
9487
|
|
|
9488
|
+
// src/deep_agent_new/middleware/patch_tool_calls.ts
|
|
9489
|
+
import {
|
|
9490
|
+
createMiddleware as createMiddleware9,
|
|
9491
|
+
ToolMessage as ToolMessage3,
|
|
9492
|
+
AIMessage as AIMessage2
|
|
9493
|
+
} from "langchain";
|
|
9494
|
+
function createPatchToolCallsMiddleware() {
|
|
9495
|
+
return createMiddleware9({
|
|
9496
|
+
name: "patchToolCallsMiddleware",
|
|
9497
|
+
beforeAgent: async (state) => {
|
|
9498
|
+
const messages = state.messages;
|
|
9499
|
+
if (!messages || messages.length === 0) {
|
|
9500
|
+
return;
|
|
9501
|
+
}
|
|
9502
|
+
const replacements = [];
|
|
9503
|
+
for (let i = 0; i < messages.length; i++) {
|
|
9504
|
+
const msg = messages[i];
|
|
9505
|
+
if (AIMessage2.isInstance(msg) && msg.tool_calls != null) {
|
|
9506
|
+
const respondedIds = /* @__PURE__ */ new Set();
|
|
9507
|
+
for (const toolCall of msg.tool_calls) {
|
|
9508
|
+
if (!toolCall.id) continue;
|
|
9509
|
+
const correspondingToolMsg = messages.slice(i).find(
|
|
9510
|
+
(m) => ToolMessage3.isInstance(m) && m.tool_call_id === toolCall.id
|
|
9511
|
+
);
|
|
9512
|
+
if (correspondingToolMsg) {
|
|
9513
|
+
respondedIds.add(toolCall.id);
|
|
9514
|
+
}
|
|
9515
|
+
}
|
|
9516
|
+
const remainingToolCalls = msg.tool_calls.filter(
|
|
9517
|
+
(toolCall) => toolCall.id && respondedIds.has(toolCall.id)
|
|
9518
|
+
);
|
|
9519
|
+
if (remainingToolCalls.length === msg.tool_calls.length) {
|
|
9520
|
+
continue;
|
|
9521
|
+
}
|
|
9522
|
+
const additionalKwargs = { ...msg.additional_kwargs };
|
|
9523
|
+
delete additionalKwargs.tool_calls;
|
|
9524
|
+
if (!msg.id) continue;
|
|
9525
|
+
replacements.push(
|
|
9526
|
+
new AIMessage2({
|
|
9527
|
+
id: msg.id,
|
|
9528
|
+
content: msg.content,
|
|
9529
|
+
name: msg.name,
|
|
9530
|
+
tool_calls: remainingToolCalls,
|
|
9531
|
+
additional_kwargs: additionalKwargs,
|
|
9532
|
+
response_metadata: msg.response_metadata
|
|
9533
|
+
})
|
|
9534
|
+
);
|
|
9535
|
+
}
|
|
9536
|
+
}
|
|
9537
|
+
if (replacements.length === 0) {
|
|
9538
|
+
return;
|
|
9539
|
+
}
|
|
9540
|
+
return {
|
|
9541
|
+
messages: replacements
|
|
9542
|
+
};
|
|
9543
|
+
}
|
|
9544
|
+
});
|
|
9545
|
+
}
|
|
9546
|
+
|
|
9547
|
+
// src/agent_lattice/builders/commonMiddleware.ts
|
|
9548
|
+
import { summarizationMiddleware } from "langchain";
|
|
9549
|
+
|
|
9484
9550
|
// src/plugin/metaSerializer.ts
|
|
9485
9551
|
function tryExtractTools(plugin) {
|
|
9486
9552
|
if (!plugin.middleware) return [];
|
|
@@ -10717,6 +10783,12 @@ actually achieve, not just what to build:
|
|
|
10717
10783
|
|
|
10718
10784
|
Record the goal model in the parent task's description ([[task-tracking]]).
|
|
10719
10785
|
|
|
10786
|
+
**HARD RULE \u2014 never guess the target.** If the goal, expected output,
|
|
10787
|
+
consumer, or usable state is unclear at ANY point before writing test
|
|
10788
|
+
cases, you MUST ask the user via ask_user_to_clarify \u2014 never proceed
|
|
10789
|
+
with an assumed expectation. A test case written against a guessed
|
|
10790
|
+
expectation validates the wrong thing. When in doubt, ask.
|
|
10791
|
+
|
|
10720
10792
|
## Goal-Driven Validation (apply to EVERY sub-skill workflow)
|
|
10721
10793
|
|
|
10722
10794
|
The agent evaluates goal achievement ITSELF via multi-dimensional test
|
|
@@ -10802,16 +10874,29 @@ Do NOT use reviewer as:
|
|
|
10802
10874
|
verification. If findings show config errors, fix and re-check.`,
|
|
10803
10875
|
"task-tracking": `---
|
|
10804
10876
|
name: task-tracking
|
|
10805
|
-
description: Manage persistent tasks
|
|
10806
|
-
|
|
10807
|
-
|
|
10877
|
+
description: Manage persistent tasks with manage_task. Universal rule:
|
|
10878
|
+
once the goal is clear and you know what to do, create the task FIRST
|
|
10879
|
+
then execute. Track parent/subtasks, update status to reflect reality,
|
|
10880
|
+
resume interrupted work. Applies to ANY multi-step agent work \u2014 not
|
|
10881
|
+
just agent building.
|
|
10808
10882
|
metadata:
|
|
10809
10883
|
domain: agent-building
|
|
10810
10884
|
verified: unverified
|
|
10811
10885
|
---
|
|
10812
10886
|
# Task Tracking \u2014 manage_task for Agent Workflows
|
|
10813
10887
|
|
|
10814
|
-
|
|
10888
|
+
**Task management is the ongoing record of a goal and its acceptance
|
|
10889
|
+
criteria** \u2014 it answers at any moment: what are we achieving, and what
|
|
10890
|
+
does "done" look like. Create a task when the goal is clear; keep its
|
|
10891
|
+
Objective and Acceptance Criteria current as work proceeds; change
|
|
10892
|
+
status only when the criteria are actually met.
|
|
10893
|
+
|
|
10894
|
+
**Universal principle**: whenever the goal is understood and the work
|
|
10895
|
+
is about to start, create a task BEFORE executing. If you can write an
|
|
10896
|
+
Objective and Acceptance Criteria, it deserves a task. This is not
|
|
10897
|
+
optional and not limited to agent-building \u2014 it applies to any
|
|
10898
|
+
multi-step work (learning, building, modifying skills, fixing, anything
|
|
10899
|
+
with a clear goal).
|
|
10815
10900
|
|
|
10816
10901
|
## When to create (and when NOT)
|
|
10817
10902
|
|
|
@@ -10828,13 +10913,29 @@ Do NOT create tasks for:
|
|
|
10828
10913
|
|
|
10829
10914
|
## Setup
|
|
10830
10915
|
|
|
10916
|
+
**A task is a living record of the GOAL + ACCEPTANCE CRITERIA** \u2014 not a
|
|
10917
|
+
todo label. Every task's description must carry:
|
|
10918
|
+
|
|
10919
|
+
- **Objective** \u2014 one measurable sentence: what result to achieve
|
|
10920
|
+
- **Acceptance Criteria** \u2014 checkboxes that define "done": when ALL
|
|
10921
|
+
are checked, the task is verifiably complete
|
|
10922
|
+
|
|
10923
|
+
The task is created when the goal is confirmed, and its description is
|
|
10924
|
+
CONTINUALLY UPDATED as the work progresses (spec evolves, criteria are
|
|
10925
|
+
met, new criteria emerge). Status changes only when the criteria are
|
|
10926
|
+
truly met \u2014 never as a workaround.
|
|
10927
|
+
|
|
10831
10928
|
- **Create the parent task when the scope is confirmed** \u2014 before
|
|
10832
10929
|
starting the first real work phase (probe/design/build):
|
|
10833
|
-
\`manage_task create(title: <goal>, description: <
|
|
10930
|
+
\`manage_task create(title: <goal>, description: <Objective + Acceptance Criteria>, ownerType: "agent")\`
|
|
10834
10931
|
Record the returned parent task id.
|
|
10835
10932
|
- **Create a subtask per phase** as you start each phase (probe /
|
|
10836
10933
|
design / build / eval / retro):
|
|
10837
|
-
\`manage_task create(title: <phase>, parentId: <parent>, ownerType: "agent")\`
|
|
10934
|
+
\`manage_task create(title: <phase>, description: <Objective + Acceptance Criteria>, parentId: <parent>, ownerType: "agent")\`
|
|
10935
|
+
- **Update the description as work proceeds**: append progress, mark
|
|
10936
|
+
criteria \`[x]\`, revise criteria when the goal model/spec changes.
|
|
10937
|
+
The task tracks the target and its acceptance \u2014 read it to know what
|
|
10938
|
+
"done" means, keep it current so it always reflects reality.
|
|
10838
10939
|
|
|
10839
10940
|
## Status discipline \u2014 MANDATORY
|
|
10840
10941
|
|
|
@@ -11142,6 +11243,9 @@ description: Run agent evaluations, interpret results, fix failures, and
|
|
|
11142
11243
|
metadata:
|
|
11143
11244
|
domain: agent-building
|
|
11144
11245
|
verified: unverified
|
|
11246
|
+
subSkills:
|
|
11247
|
+
- eval-design-tests
|
|
11248
|
+
- eval-run-and-govern
|
|
11145
11249
|
---
|
|
11146
11250
|
# Eval Verify \u2014 Run Evaluations and Upgrade Trust
|
|
11147
11251
|
|
|
@@ -11158,6 +11262,13 @@ verified: unverified
|
|
|
11158
11262
|
parent (eval-{parent-id}) \u2014 see Layered verification below.
|
|
11159
11263
|
2. \`manage_eval create_case(suiteId, ...)\` per sample or scenario
|
|
11160
11264
|
Required: inputMessage, steps=[{agent_id}], outputType, contentAssertion
|
|
11265
|
+
**contentAssertion MUST come from the confirmed expected output spec**
|
|
11266
|
+
(learn-capability Phase 2.6) \u2014 never invent expectations at
|
|
11267
|
+
case-writing time. If a needed expectation is not in the spec, extend
|
|
11268
|
+
the spec with user confirmation first.
|
|
11269
|
+
**HARD RULE**: if the target/expected output is unclear at this
|
|
11270
|
+
point, STOP and ask the user (ask_user_to_clarify) \u2014 do not write a
|
|
11271
|
+
case with a guessed expectation.
|
|
11161
11272
|
|
|
11162
11273
|
## Suites per skill, by source
|
|
11163
11274
|
|
|
@@ -11501,10 +11612,20 @@ async function resolveConnections(type, connections, tenantId2) {
|
|
|
11501
11612
|
throw err;
|
|
11502
11613
|
}
|
|
11503
11614
|
}
|
|
11504
|
-
async function createCommonMiddlewares(middlewareConfigs, filesystemBackend, fsIsExised, tenantId2) {
|
|
11615
|
+
async function createCommonMiddlewares(middlewareConfigs, filesystemBackend, fsIsExised, tenantId2, model) {
|
|
11505
11616
|
const middlewares = [];
|
|
11506
11617
|
middlewares.push(createUnknownToolHandlerMiddleware());
|
|
11507
11618
|
middlewares.push(createModelSelectorMiddleware());
|
|
11619
|
+
middlewares.push(createPatchToolCallsMiddleware());
|
|
11620
|
+
if (model) {
|
|
11621
|
+
middlewares.push(
|
|
11622
|
+
summarizationMiddleware({
|
|
11623
|
+
model,
|
|
11624
|
+
trigger: { tokens: 17e4 },
|
|
11625
|
+
keep: { messages: 6 }
|
|
11626
|
+
})
|
|
11627
|
+
);
|
|
11628
|
+
}
|
|
11508
11629
|
const filesystemConfig = middlewareConfigs.find((m) => m.type === "filesystem");
|
|
11509
11630
|
const clawConfig = middlewareConfigs.find((m) => m.type === "claw");
|
|
11510
11631
|
const needsFilesystemBackend = filesystemConfig?.enabled || clawConfig?.enabled;
|
|
@@ -11836,7 +11957,7 @@ var ReActAgentGraphBuilder = class {
|
|
|
11836
11957
|
const stateSchema2 = createReactAgentSchema(params.stateSchema);
|
|
11837
11958
|
const middlewareConfigs = params.middleware || [];
|
|
11838
11959
|
const filesystemBackend = createFilesystemBackendFactory(middlewareConfigs);
|
|
11839
|
-
const middlewares = await createCommonMiddlewares(middlewareConfigs, filesystemBackend, void 0, params.tenantId);
|
|
11960
|
+
const middlewares = await createCommonMiddlewares(middlewareConfigs, filesystemBackend, void 0, params.tenantId, params.model);
|
|
11840
11961
|
return createAgent({
|
|
11841
11962
|
model: params.model,
|
|
11842
11963
|
tools,
|
|
@@ -11854,17 +11975,16 @@ var ReActAgentGraphBuilder = class {
|
|
|
11854
11975
|
import {
|
|
11855
11976
|
createAgent as createAgent3,
|
|
11856
11977
|
humanInTheLoopMiddleware as humanInTheLoopMiddleware2,
|
|
11857
|
-
anthropicPromptCachingMiddleware
|
|
11858
|
-
summarizationMiddleware
|
|
11978
|
+
anthropicPromptCachingMiddleware
|
|
11859
11979
|
} from "langchain";
|
|
11860
11980
|
|
|
11861
11981
|
// src/deep_agent_new/middleware/subagents.ts
|
|
11862
11982
|
import { z as z42 } from "zod/v3";
|
|
11863
11983
|
import {
|
|
11864
|
-
createMiddleware as
|
|
11984
|
+
createMiddleware as createMiddleware11,
|
|
11865
11985
|
createAgent as createAgent2,
|
|
11866
11986
|
tool as tool40,
|
|
11867
|
-
ToolMessage as
|
|
11987
|
+
ToolMessage as ToolMessage4,
|
|
11868
11988
|
humanInTheLoopMiddleware
|
|
11869
11989
|
} from "langchain";
|
|
11870
11990
|
import { Command as Command3, getCurrentTaskInput as getCurrentTaskInput2, GraphInterrupt as GraphInterrupt3 } from "@langchain/langgraph";
|
|
@@ -13810,7 +13930,7 @@ var AgentInstanceManager = class _AgentInstanceManager {
|
|
|
13810
13930
|
var agentInstanceManager = AgentInstanceManager.getInstance();
|
|
13811
13931
|
|
|
13812
13932
|
// src/middlewares/taskMiddleware.ts
|
|
13813
|
-
import { createMiddleware as
|
|
13933
|
+
import { createMiddleware as createMiddleware10, tool as tool39 } from "langchain";
|
|
13814
13934
|
import { z as z41 } from "zod";
|
|
13815
13935
|
import { GraphInterrupt as GraphInterrupt2, interrupt as interrupt3 } from "@langchain/langgraph";
|
|
13816
13936
|
function getRunConfig(config) {
|
|
@@ -14118,26 +14238,37 @@ function createTaskMiddleware() {
|
|
|
14118
14238
|
});
|
|
14119
14239
|
}
|
|
14120
14240
|
};
|
|
14121
|
-
return
|
|
14241
|
+
return createMiddleware10({
|
|
14122
14242
|
name: "TaskMiddleware",
|
|
14123
14243
|
contextSchema,
|
|
14124
14244
|
wrapModelCall: async (request, handler) => {
|
|
14125
14245
|
const taskPrompt = `## Task Management
|
|
14126
14246
|
|
|
14127
|
-
You
|
|
14247
|
+
You have the \`manage_task\` tool to track work. Task management is the
|
|
14248
|
+
ongoing record of a GOAL and its ACCEPTANCE CRITERIA.
|
|
14128
14249
|
|
|
14129
|
-
### When to create a task
|
|
14250
|
+
### When to create a task (universal rule)
|
|
14251
|
+
- The goal is clear and you are about to start real work \u2192 create the
|
|
14252
|
+
parent task FIRST (with Objective + Acceptance Criteria in the
|
|
14253
|
+
description), then execute. This is a core duty, not optional.
|
|
14130
14254
|
- The user explicitly asks you to track, manage, or follow up on work
|
|
14131
14255
|
- The work spans multiple sessions or might need resumption later
|
|
14132
14256
|
- The user needs to review or approve output before it is considered done
|
|
14133
14257
|
- There are multiple independent work items the user wants visibility into
|
|
14134
14258
|
|
|
14135
14259
|
### When NOT to create a task
|
|
14260
|
+
- Goal not yet clear (still clarifying) \u2014 clarify first, then create
|
|
14136
14261
|
- One-shot lookups or simple Q&A ("what is X?", "search for Y")
|
|
14137
14262
|
- Internal exploration steps you take to understand the problem (use \`write_todos\` for your execution plan instead)
|
|
14138
14263
|
- Trivial single-step actions that complete in the same turn
|
|
14139
14264
|
- Conversational or informational requests with no deliverable
|
|
14140
14265
|
|
|
14266
|
+
### Keep the task current
|
|
14267
|
+
A task is the living record of the goal + its acceptance criteria.
|
|
14268
|
+
Update the description as work proceeds: check off criteria as met,
|
|
14269
|
+
revise criteria when scope changes, append progress. Status changes
|
|
14270
|
+
only when the criteria are truly met.
|
|
14271
|
+
|
|
14141
14272
|
### Ownership defaults
|
|
14142
14273
|
- No params: ownerType defaults to "user" with current user's ID
|
|
14143
14274
|
- ownerType="agent": auto-fills ownerId from current agent (subtask for yourself)
|
|
@@ -14191,6 +14322,29 @@ var taskPlugin = {
|
|
|
14191
14322
|
skills: {
|
|
14192
14323
|
"task-definition": `## Using manage_task
|
|
14193
14324
|
|
|
14325
|
+
### When to create a task (universal rule)
|
|
14326
|
+
|
|
14327
|
+
Create a task BEFORE executing whenever the goal is clear and you know
|
|
14328
|
+
what to do \u2014 not just for long or complex work:
|
|
14329
|
+
|
|
14330
|
+
- Goal is understood and you are about to start real work \u2192 create the
|
|
14331
|
+
parent task FIRST, then execute. The task tracks the work.
|
|
14332
|
+
- Goal is NOT yet clear (still clarifying, gathering requirements) \u2192
|
|
14333
|
+
do NOT create a task yet. Clarify first, create the task once scope
|
|
14334
|
+
is defined.
|
|
14335
|
+
- One-shot lookups, trivial single-step actions, or internal reasoning
|
|
14336
|
+
\u2192 no task needed.
|
|
14337
|
+
|
|
14338
|
+
Rule of thumb: if you can write an Objective and Acceptance Criteria
|
|
14339
|
+
for it, create the task before doing it. Work without a task = work
|
|
14340
|
+
without a contract.
|
|
14341
|
+
|
|
14342
|
+
**A task is the living record of the goal + its acceptance criteria.**
|
|
14343
|
+
Keep the description current as work proceeds: update the Objective
|
|
14344
|
+
when the target evolves, check off criteria as they are met, revise
|
|
14345
|
+
criteria when scope changes. Reading the task always tells you what
|
|
14346
|
+
"done" means; an outdated task is a broken contract.
|
|
14347
|
+
|
|
14194
14348
|
### Task description format
|
|
14195
14349
|
|
|
14196
14350
|
When creating a task with manage_task, write the description in this Markdown structure:
|
|
@@ -14392,7 +14546,7 @@ function returnCommandWithStateUpdate(result, toolCallId) {
|
|
|
14392
14546
|
update: {
|
|
14393
14547
|
...stateUpdate,
|
|
14394
14548
|
messages: [
|
|
14395
|
-
new
|
|
14549
|
+
new ToolMessage4({
|
|
14396
14550
|
content: lastMessage?.content || "Task Failed to complete",
|
|
14397
14551
|
tool_call_id: toolCallId,
|
|
14398
14552
|
name: "task"
|
|
@@ -14585,7 +14739,7 @@ You are executing a persistent task (ID: ${input.taskId}). Use manage_task.updat
|
|
|
14585
14739
|
return new Command3({
|
|
14586
14740
|
update: {
|
|
14587
14741
|
messages: [
|
|
14588
|
-
new
|
|
14742
|
+
new ToolMessage4({
|
|
14589
14743
|
content: `Async task started: ${subagent_thread_id}
|
|
14590
14744
|
${description}
|
|
14591
14745
|
The result will be delivered as a notification when complete. Do not poll.`,
|
|
@@ -14619,7 +14773,7 @@ The result will be delivered as a notification when complete. Do not poll.`,
|
|
|
14619
14773
|
return new Command3({
|
|
14620
14774
|
update: {
|
|
14621
14775
|
messages: [
|
|
14622
|
-
new
|
|
14776
|
+
new ToolMessage4({
|
|
14623
14777
|
content: error instanceof Error ? error.message : "Task Failed to complete",
|
|
14624
14778
|
tool_call_id: config.toolCall.id,
|
|
14625
14779
|
name: "task"
|
|
@@ -14856,7 +15010,7 @@ function createSubAgentMiddleware(options) {
|
|
|
14856
15010
|
);
|
|
14857
15011
|
}
|
|
14858
15012
|
const effectiveSystemPrompt = allowAsync ? systemPrompt + getAsyncPromptText() : systemPrompt;
|
|
14859
|
-
return
|
|
15013
|
+
return createMiddleware11({
|
|
14860
15014
|
name: "subAgentMiddleware",
|
|
14861
15015
|
tools: allTools,
|
|
14862
15016
|
wrapModelCall: async (request, handler) => {
|
|
@@ -14875,53 +15029,6 @@ ${effectiveSystemPrompt}` : effectiveSystemPrompt;
|
|
|
14875
15029
|
});
|
|
14876
15030
|
}
|
|
14877
15031
|
|
|
14878
|
-
// src/deep_agent_new/middleware/patch_tool_calls.ts
|
|
14879
|
-
import {
|
|
14880
|
-
createMiddleware as createMiddleware11,
|
|
14881
|
-
ToolMessage as ToolMessage4,
|
|
14882
|
-
AIMessage as AIMessage2
|
|
14883
|
-
} from "langchain";
|
|
14884
|
-
function createPatchToolCallsMiddleware() {
|
|
14885
|
-
return createMiddleware11({
|
|
14886
|
-
name: "patchToolCallsMiddleware",
|
|
14887
|
-
beforeAgent: async (state) => {
|
|
14888
|
-
const messages = state.messages;
|
|
14889
|
-
if (!messages || messages.length === 0) {
|
|
14890
|
-
return;
|
|
14891
|
-
}
|
|
14892
|
-
const patchedMessages = [];
|
|
14893
|
-
for (let i = 0; i < messages.length; i++) {
|
|
14894
|
-
const msg = messages[i];
|
|
14895
|
-
patchedMessages.push(msg);
|
|
14896
|
-
if (AIMessage2.isInstance(msg) && msg.tool_calls != null) {
|
|
14897
|
-
for (const toolCall of msg.tool_calls) {
|
|
14898
|
-
const correspondingToolMsg = messages.slice(i).find(
|
|
14899
|
-
(m) => ToolMessage4.isInstance(m) && m.tool_call_id === toolCall.id
|
|
14900
|
-
);
|
|
14901
|
-
if (!correspondingToolMsg) {
|
|
14902
|
-
const toolMsg = `Tool call ${toolCall.name} with id ${toolCall.id} was cancelled - another message came in before it could be completed.`;
|
|
14903
|
-
patchedMessages.push(
|
|
14904
|
-
new ToolMessage4({
|
|
14905
|
-
content: toolMsg,
|
|
14906
|
-
name: toolCall.name,
|
|
14907
|
-
tool_call_id: toolCall.id
|
|
14908
|
-
})
|
|
14909
|
-
);
|
|
14910
|
-
}
|
|
14911
|
-
}
|
|
14912
|
-
}
|
|
14913
|
-
}
|
|
14914
|
-
if (patchedMessages.length === messages.length) {
|
|
14915
|
-
return;
|
|
14916
|
-
}
|
|
14917
|
-
return {
|
|
14918
|
-
messages: patchedMessages.slice(messages.length)
|
|
14919
|
-
// only the new ToolMessage patches
|
|
14920
|
-
};
|
|
14921
|
-
}
|
|
14922
|
-
});
|
|
14923
|
-
}
|
|
14924
|
-
|
|
14925
15032
|
// src/deep_agent_new/middleware/date.ts
|
|
14926
15033
|
import { createMiddleware as createMiddleware12, tool as tool41 } from "langchain";
|
|
14927
15034
|
import { z as z43 } from "zod";
|
|
@@ -17834,36 +17941,20 @@ ${BASE_PROMPT}` : BASE_PROMPT;
|
|
|
17834
17941
|
createFilesystemMiddleware({
|
|
17835
17942
|
backend: filesystemBackend
|
|
17836
17943
|
}),
|
|
17837
|
-
// Subagent middleware: Automatic conversation summarization when token limits are approached
|
|
17838
|
-
summarizationMiddleware({
|
|
17839
|
-
model,
|
|
17840
|
-
trigger: { tokens: 17e4 },
|
|
17841
|
-
keep: { messages: 6 }
|
|
17842
|
-
}),
|
|
17843
17944
|
// Subagent middleware: Anthropic prompt caching for improved performance
|
|
17844
17945
|
anthropicPromptCachingMiddleware({
|
|
17845
17946
|
unsupportedModelBehavior: "ignore"
|
|
17846
17947
|
}),
|
|
17847
|
-
// Subagent middleware: Patches tool calls for compatibility
|
|
17848
|
-
createPatchToolCallsMiddleware(),
|
|
17849
17948
|
...customMiddleware
|
|
17850
17949
|
],
|
|
17851
17950
|
defaultInterruptOn: interruptOn,
|
|
17852
17951
|
subagents,
|
|
17853
17952
|
generalPurposeAgent: true
|
|
17854
17953
|
}),
|
|
17855
|
-
// Automatically summarizes conversation history when token limits are approached
|
|
17856
|
-
summarizationMiddleware({
|
|
17857
|
-
model,
|
|
17858
|
-
trigger: { tokens: 17e4 },
|
|
17859
|
-
keep: { messages: 6 }
|
|
17860
|
-
}),
|
|
17861
17954
|
// Enables Anthropic prompt caching for improved performance and reduced costs
|
|
17862
17955
|
anthropicPromptCachingMiddleware({
|
|
17863
17956
|
unsupportedModelBehavior: "ignore"
|
|
17864
|
-
})
|
|
17865
|
-
// Patches tool calls to ensure compatibility across different model providers
|
|
17866
|
-
createPatchToolCallsMiddleware()
|
|
17957
|
+
})
|
|
17867
17958
|
];
|
|
17868
17959
|
if (interruptOn) {
|
|
17869
17960
|
middleware.push(humanInTheLoopMiddleware2({ interruptOn }));
|
|
@@ -17918,7 +18009,7 @@ var DeepAgentGraphBuilder = class {
|
|
|
17918
18009
|
}));
|
|
17919
18010
|
const middlewareConfigs = params.middleware || [];
|
|
17920
18011
|
const filesystemBackend = createFilesystemBackendFactory(middlewareConfigs);
|
|
17921
|
-
const middlewares = await createCommonMiddlewares(middlewareConfigs, filesystemBackend, true, params.tenantId);
|
|
18012
|
+
const middlewares = await createCommonMiddlewares(middlewareConfigs, filesystemBackend, true, params.tenantId, params.model);
|
|
17922
18013
|
const deepAgent = createDeepAgent({
|
|
17923
18014
|
tools,
|
|
17924
18015
|
model: params.model,
|
|
@@ -19534,7 +19625,7 @@ var TeamAgentGraphBuilder = class {
|
|
|
19534
19625
|
});
|
|
19535
19626
|
const middlewareConfigs = params.middleware || [];
|
|
19536
19627
|
let filesystemBackend = createFilesystemBackendFactory(middlewareConfigs);
|
|
19537
|
-
const middlewares = await createCommonMiddlewares(middlewareConfigs);
|
|
19628
|
+
const middlewares = await createCommonMiddlewares(middlewareConfigs, void 0, void 0, void 0, params.model);
|
|
19538
19629
|
if (!filesystemBackend) {
|
|
19539
19630
|
filesystemBackend = async (config2) => {
|
|
19540
19631
|
return new StateBackend(config2);
|
|
@@ -19951,7 +20042,7 @@ var WorkflowAgentGraphBuilder = class {
|
|
|
19951
20042
|
const checkpointer = getCheckpointSaver("default");
|
|
19952
20043
|
const tools = params.tools.map((t) => t.executor).filter(Boolean);
|
|
19953
20044
|
const middlewareConfigs = params.middleware || [];
|
|
19954
|
-
const middlewares = await createCommonMiddlewares(middlewareConfigs, void 0, false, params.tenantId);
|
|
20045
|
+
const middlewares = await createCommonMiddlewares(middlewareConfigs, void 0, false, params.tenantId, params.model);
|
|
19955
20046
|
const askMiddlewares = await createCommonMiddlewares([
|
|
19956
20047
|
{
|
|
19957
20048
|
id: "ask_user_to_clarify",
|
|
@@ -19961,7 +20052,7 @@ var WorkflowAgentGraphBuilder = class {
|
|
|
19961
20052
|
enabled: true,
|
|
19962
20053
|
config: {}
|
|
19963
20054
|
}
|
|
19964
|
-
], void 0, false);
|
|
20055
|
+
], void 0, false, void 0, params.model);
|
|
19965
20056
|
const noWrapMiddlewares = stripWrapModelCallHook(middlewares);
|
|
19966
20057
|
const noWrapAskMiddlewares = stripWrapModelCallHook(askMiddlewares);
|
|
19967
20058
|
console.log(`[WF BUILDER] building default agent | toolCount=${tools.length} | middlewareCount=${middlewares.length}`);
|
|
@@ -21638,6 +21729,14 @@ Call the \`skill\` tool with skill_name: "agent-architecture" to load the
|
|
|
21638
21729
|
authoritative workflow. Never announce that you will follow a skill \u2014
|
|
21639
21730
|
load it and follow its content. If the load fails, retry once, then report it.
|
|
21640
21731
|
|
|
21732
|
+
TASK MANAGEMENT IS A CORE DUTY, not a per-skill option. Whenever the
|
|
21733
|
+
goal is clear and you know what to do, create a task FIRST (manage_task)
|
|
21734
|
+
before executing \u2014 for any multi-step work: learning, building,
|
|
21735
|
+
modifying, fixing, anything with an Objective and Acceptance Criteria.
|
|
21736
|
+
Subtasks per work item. Status must reflect reality. See [[task-tracking]].
|
|
21737
|
+
The sub-skills below only ADD their own task details on top of this
|
|
21738
|
+
universal duty.
|
|
21739
|
+
|
|
21641
21740
|
Your sub-skills (accessible via the MOC or direct loading):
|
|
21642
21741
|
- [[learn-capability]] \u2014 Learn from any source material \u2192 skills + agents
|
|
21643
21742
|
- [[agent-build]] \u2014 Design and build single agents (REACT/DEEP_AGENT)
|
|
@@ -21802,7 +21901,15 @@ var agentArchitectConfig = {
|
|
|
21802
21901
|
id: "task",
|
|
21803
21902
|
type: "task",
|
|
21804
21903
|
name: "Task",
|
|
21805
|
-
description: "
|
|
21904
|
+
description: "Core architect duty: once the goal is clear, create tasks to track every multi-step piece of work (learning, building, modifying, fixing). Subtasks per work item; status reflects reality.",
|
|
21905
|
+
enabled: true,
|
|
21906
|
+
config: {}
|
|
21907
|
+
},
|
|
21908
|
+
{
|
|
21909
|
+
id: "code_eval",
|
|
21910
|
+
type: "code_eval",
|
|
21911
|
+
name: "Code Evaluation",
|
|
21912
|
+
description: "Execute shell commands in the sandbox to support agent creation: unzip files, process data, run helper scripts. Distinct from the eval assessment system (run_eval).",
|
|
21806
21913
|
enabled: true,
|
|
21807
21914
|
config: {}
|
|
21808
21915
|
},
|
|
@@ -25424,6 +25531,15 @@ function parseJudgeVerdict(raw) {
|
|
|
25424
25531
|
return { error: error instanceof Error ? error.message : String(error) };
|
|
25425
25532
|
}
|
|
25426
25533
|
}
|
|
25534
|
+
var MAX_INTERRUPT_RESUMES = 5;
|
|
25535
|
+
function resolveInterruptResponse(policy, interrupt5) {
|
|
25536
|
+
if (policy.mode === "auto-approve") return policy.value ?? "\u540C\u610F";
|
|
25537
|
+
if (policy.mode === "auto-reject") return policy.value ?? "\u62D2\u7EDD";
|
|
25538
|
+
return policy.value ?? "";
|
|
25539
|
+
}
|
|
25540
|
+
function interruptValueText(value) {
|
|
25541
|
+
return typeof value === "string" ? value : JSON.stringify(value ?? "");
|
|
25542
|
+
}
|
|
25427
25543
|
var _LatticeEval = class _LatticeEval {
|
|
25428
25544
|
constructor(config = {}) {
|
|
25429
25545
|
this.inMemoryLogs = [];
|
|
@@ -25490,7 +25606,8 @@ var _LatticeEval = class _LatticeEval {
|
|
|
25490
25606
|
return acc;
|
|
25491
25607
|
}, {});
|
|
25492
25608
|
}
|
|
25493
|
-
async executeAgentStep(step, threadId, inputMessage, files) {
|
|
25609
|
+
async executeAgentStep(step, threadId, inputMessage, files, interruptPolicy) {
|
|
25610
|
+
const hitlEvents = [];
|
|
25494
25611
|
this.log("Executing agent step", {
|
|
25495
25612
|
agent_id: step.agent_id,
|
|
25496
25613
|
thread_id: threadId,
|
|
@@ -25508,19 +25625,74 @@ var _LatticeEval = class _LatticeEval {
|
|
|
25508
25625
|
};
|
|
25509
25626
|
const agent = agentInstanceManager.getAgent(agentParams);
|
|
25510
25627
|
try {
|
|
25511
|
-
const
|
|
25512
|
-
|
|
25513
|
-
|
|
25514
|
-
|
|
25628
|
+
const stepInput = {
|
|
25629
|
+
message: step.override_message || inputMessage,
|
|
25630
|
+
files: this.buildFileEntries(files)
|
|
25631
|
+
};
|
|
25632
|
+
let result = await agent.invokeWithState({ input: stepInput });
|
|
25633
|
+
let resumeCount = 0;
|
|
25634
|
+
let pendingInterrupt;
|
|
25635
|
+
let interrupts = Array.isArray(result?.__interrupt__) ? result.__interrupt__ : [];
|
|
25636
|
+
while (interrupts.length > 0) {
|
|
25637
|
+
const interrupt5 = interrupts[0];
|
|
25638
|
+
if (!interrupt5) break;
|
|
25639
|
+
const policy = interruptPolicy;
|
|
25640
|
+
if (!policy || policy.mode === "stop" || resumeCount >= MAX_INTERRUPT_RESUMES) {
|
|
25641
|
+
pendingInterrupt = interrupt5;
|
|
25642
|
+
break;
|
|
25515
25643
|
}
|
|
25516
|
-
|
|
25644
|
+
const response = resolveInterruptResponse(policy, interrupt5);
|
|
25645
|
+
hitlEvents.push({
|
|
25646
|
+
type: "interrupt",
|
|
25647
|
+
id: interrupt5.id,
|
|
25648
|
+
value: interrupt5.value
|
|
25649
|
+
});
|
|
25650
|
+
this.log("Auto-resolving HITL interrupt", {
|
|
25651
|
+
agent_id: step.agent_id,
|
|
25652
|
+
thread_id: threadId,
|
|
25653
|
+
mode: policy.mode,
|
|
25654
|
+
interrupt_id: interrupt5.id,
|
|
25655
|
+
response,
|
|
25656
|
+
resume_count: resumeCount + 1
|
|
25657
|
+
});
|
|
25658
|
+
result = await agent.invokeWithState({ input: stepInput, command: { resume: response } });
|
|
25659
|
+
hitlEvents.push({
|
|
25660
|
+
type: "interrupt_response",
|
|
25661
|
+
id: interrupt5.id,
|
|
25662
|
+
mode: policy.mode,
|
|
25663
|
+
response
|
|
25664
|
+
});
|
|
25665
|
+
resumeCount++;
|
|
25666
|
+
interrupts = Array.isArray(result?.__interrupt__) ? result.__interrupt__ : [];
|
|
25667
|
+
}
|
|
25668
|
+
if (pendingInterrupt) {
|
|
25669
|
+
hitlEvents.push({
|
|
25670
|
+
type: "interrupt",
|
|
25671
|
+
id: pendingInterrupt.id,
|
|
25672
|
+
value: pendingInterrupt.value
|
|
25673
|
+
});
|
|
25674
|
+
this.log("Agent step interrupted by HITL (human input requested)", {
|
|
25675
|
+
agent_id: step.agent_id,
|
|
25676
|
+
thread_id: threadId,
|
|
25677
|
+
interrupt_id: pendingInterrupt.id,
|
|
25678
|
+
auto_resolved: resumeCount
|
|
25679
|
+
});
|
|
25680
|
+
} else {
|
|
25681
|
+
this.log("Agent step completed", {
|
|
25682
|
+
agent_id: step.agent_id,
|
|
25683
|
+
thread_id: threadId,
|
|
25684
|
+
response_keys: result ? Object.keys(result) : [],
|
|
25685
|
+
auto_resolved: resumeCount
|
|
25686
|
+
});
|
|
25687
|
+
}
|
|
25517
25688
|
const responseData = { success: true, ...result };
|
|
25518
|
-
|
|
25519
|
-
|
|
25520
|
-
|
|
25521
|
-
|
|
25522
|
-
|
|
25523
|
-
|
|
25689
|
+
return {
|
|
25690
|
+
threadId,
|
|
25691
|
+
responseData,
|
|
25692
|
+
interrupted: pendingInterrupt ? true : void 0,
|
|
25693
|
+
interrupt: pendingInterrupt,
|
|
25694
|
+
hitlEvents
|
|
25695
|
+
};
|
|
25524
25696
|
} catch (error) {
|
|
25525
25697
|
const message = error instanceof Error ? error.message : String(error);
|
|
25526
25698
|
this.log("Agent step failed", {
|
|
@@ -25583,15 +25755,32 @@ var _LatticeEval = class _LatticeEval {
|
|
|
25583
25755
|
});
|
|
25584
25756
|
let currentThreadId = threadId;
|
|
25585
25757
|
let lastResponseData = null;
|
|
25758
|
+
let interrupt5;
|
|
25586
25759
|
for (const step of evalCase.steps) {
|
|
25587
25760
|
const result = await this.executeAgentStep(
|
|
25588
25761
|
step,
|
|
25589
25762
|
currentThreadId,
|
|
25590
25763
|
evalCase.input.message,
|
|
25591
|
-
evalCase.input.files || {}
|
|
25764
|
+
evalCase.input.files || {},
|
|
25765
|
+
evalCase.interruptPolicy
|
|
25592
25766
|
);
|
|
25593
25767
|
currentThreadId = result.threadId;
|
|
25594
25768
|
lastResponseData = result.responseData;
|
|
25769
|
+
for (const evt of result.hitlEvents) {
|
|
25770
|
+
if (evt.type === "interrupt") {
|
|
25771
|
+
this.lastMessages.push({
|
|
25772
|
+
role: "interrupt",
|
|
25773
|
+
content: `HITL \u6682\u505C\uFF1AAgent \u8BF7\u6C42\u4EBA\u5DE5\u8F93\u5165 \u2014 ${interruptValueText(evt.value)}`,
|
|
25774
|
+
id: evt.id
|
|
25775
|
+
});
|
|
25776
|
+
} else {
|
|
25777
|
+
this.lastMessages.push({
|
|
25778
|
+
role: "interrupt_response",
|
|
25779
|
+
content: `\u5DF2\u81EA\u52A8\u54CD\u5E94\uFF08\u6D4B\u8BD5\u7B56\u7565 ${evt.mode}\uFF09\uFF1A${evt.response}`,
|
|
25780
|
+
id: evt.id
|
|
25781
|
+
});
|
|
25782
|
+
}
|
|
25783
|
+
}
|
|
25595
25784
|
const existingIds = new Set(this.lastMessages.map((m) => m.id).filter(Boolean));
|
|
25596
25785
|
if (result.responseData?.messages && Array.isArray(result.responseData.messages)) {
|
|
25597
25786
|
for (const msg of result.responseData.messages) {
|
|
@@ -25613,6 +25802,13 @@ var _LatticeEval = class _LatticeEval {
|
|
|
25613
25802
|
} else {
|
|
25614
25803
|
content = String(msg.content || "");
|
|
25615
25804
|
}
|
|
25805
|
+
if (Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {
|
|
25806
|
+
const toolCallStr = msg.tool_calls.map(
|
|
25807
|
+
(tc) => `tool_call: ${tc.name}(${JSON.stringify(tc.args ?? {})})`
|
|
25808
|
+
).join("\n");
|
|
25809
|
+
content = content ? `${content}
|
|
25810
|
+
${toolCallStr}` : toolCallStr;
|
|
25811
|
+
}
|
|
25616
25812
|
this.lastMessages.push({
|
|
25617
25813
|
role,
|
|
25618
25814
|
content,
|
|
@@ -25624,13 +25820,21 @@ var _LatticeEval = class _LatticeEval {
|
|
|
25624
25820
|
}
|
|
25625
25821
|
}
|
|
25626
25822
|
}
|
|
25823
|
+
if (result.interrupted) {
|
|
25824
|
+
interrupt5 = result.interrupt;
|
|
25825
|
+
this.log("Case paused for HITL \u2014 remaining steps skipped; judge will evaluate the pause", {
|
|
25826
|
+
case_id: evalCase.caseId,
|
|
25827
|
+
interrupt_id: interrupt5?.id
|
|
25828
|
+
});
|
|
25829
|
+
break;
|
|
25830
|
+
}
|
|
25627
25831
|
}
|
|
25628
25832
|
this.log("All agent steps completed", {
|
|
25629
25833
|
case_id: evalCase.caseId,
|
|
25630
25834
|
final_thread_id: currentThreadId,
|
|
25631
25835
|
message_count: this.lastMessages.length
|
|
25632
25836
|
});
|
|
25633
|
-
const finalOutput = this.extractFinalMessage(lastResponseData);
|
|
25837
|
+
const finalOutput = interrupt5 ? typeof interrupt5.value === "string" ? interrupt5.value : JSON.stringify(interrupt5.value ?? "") : this.extractFinalMessage(lastResponseData);
|
|
25634
25838
|
this.lastFinalOutput = finalOutput;
|
|
25635
25839
|
const trajectory = this.buildTrajectory();
|
|
25636
25840
|
this.log("Final output extracted", {
|
|
@@ -25689,6 +25893,8 @@ ${rubricsSection}
|
|
|
25689
25893
|
3. **\u8FC7\u7A0B\u6821\u9A8C**\uFF1A\u5982\u679C"\u6267\u884C\u8FC7\u7A0B"\u663E\u793A Agent \u672A\u6267\u884C\u5FC5\u8981\u7684\u4E2D\u95F4\u6B65\u9AA4\uFF08\u5982\u5E94\u8C03\u7528\u5DE5\u5177\u800C\u672A\u8C03\u7528\uFF09\uFF0C\u5373\u4F7F\u6700\u7EC8\u8F93\u51FA\u770B\u4F3C\u5408\u7406\uFF0C\u4E5F\u5E94\u5728\u5BF9\u5E94\u6307\u6807\u4E0A\u6263\u5206\u3002
|
|
25690
25894
|
4. **\u8BC1\u636E\u5BFC\u5411**\uFF1A\u5728\u7ED9\u51FA\u539F\u56E0\uFF08reason\uFF09\u65F6\uFF0C\u5FC5\u987B\u5F15\u7528\u6267\u884C\u8FC7\u7A0B\u6216\u6700\u7EC8\u8F93\u51FA\u4E2D\u7684\u5177\u4F53\u5185\u5BB9\u3002
|
|
25691
25895
|
5. **\u52A0\u6743\u8BA1\u7B97**\uFF1A\u6700\u7EC8\u5206\u6570\u4E3A\u5404\u9879\u6307\u6807\u5F97\u5206\u4E0E\u5176\u6743\u91CD\u7684\u4E58\u79EF\u4E4B\u548C\uFF080-100\u5206\u5236\uFF09\u3002
|
|
25896
|
+
6. **HITL \u4E2D\u65AD\u5224\u5B9A**\uFF1A\u5982\u679C\u6267\u884C\u8FC7\u7A0B\u4E2D\u51FA\u73B0\u300CHITL \u6682\u505C\uFF1AAgent \u8BF7\u6C42\u4EBA\u5DE5\u8F93\u5165\u300D\u6761\u76EE\uFF0C\u8BF4\u660E Agent \u5728\u7B49\u5F85\u4EBA\u5DE5\u786E\u8BA4\u3002\u8BF7\u628A\u5B83\u5F53\u4F5C\u88AB\u6D4B\u4E1A\u52A1\u884C\u4E3A\u6765\u8BC4\u5224\uFF1A\u82E5\u671F\u671B\u8F93\u51FA\u8981\u6C42\u81EA\u4E3B\u5B8C\u6210\uFF08\u5982"\u65E0\u9700\u786E\u8BA4\u81EA\u52A8\u6267\u884C"\uFF09\uFF0C\u8BF7\u6C42\u4EBA\u5DE5\u8F93\u5165\u5E94\u5224\u5931\u8D25\uFF1B\u82E5\u671F\u671B\u8F93\u51FA\u8981\u6C42\u5148\u83B7\u5F97\u786E\u8BA4\u6216\u6279\u51C6\uFF08\u5982"\u6267\u884C\u524D\u5FC5\u987B\u8BF7\u6C42\u6279\u51C6"\uFF09\uFF0C\u8BF7\u6C42\u4EBA\u5DE5\u8F93\u5165\u662F\u6B63\u786E\u884C\u4E3A\uFF0C\u5E94\u7ED3\u5408\u5176\u65F6\u673A\u4E0E\u5185\u5BB9\u5224\u5B9A\u4E3A\u901A\u8FC7\u6216\u6309\u6307\u6807\u7ED9\u5206\u3002
|
|
25897
|
+
7. **HITL \u81EA\u52A8\u54CD\u5E94\u5224\u5B9A**\uFF1A\u5982\u679C\u300CHITL \u6682\u505C\u300D\u6761\u76EE\u4E4B\u540E\u51FA\u73B0\u300C\u5DF2\u81EA\u52A8\u54CD\u5E94\uFF08\u6D4B\u8BD5\u7B56\u7565 auto-approve/auto-reject/canned-response\uFF09\u300D\u6761\u76EE\uFF0C\u8BF4\u660E\u6D4B\u8BD5\u6846\u67B6\u6CE8\u5165\u4E86\u4EBA\u5DE5\u56DE\u590D\u3001\u6D41\u7A0B\u5DF2\u7EE7\u7EED\u2014\u2014\u8BF7\u6309**\u5B8C\u6574\u6D41\u7A0B**\u8BC4\u5224\u6682\u505C\u4E4B\u540E\u7684\u884C\u4E3A\uFF08\u5982\u6279\u51C6\u540E\u662F\u5426\u6B63\u786E\u6267\u884C\u4E86\u64CD\u4F5C\uFF09\uFF0C\u5E76\u6838\u5BF9\u81EA\u52A8\u54CD\u5E94\u5185\u5BB9\u662F\u5426\u7B26\u5408\u4EBA\u5DE5\u56DE\u590D\u7684\u5408\u7406\u9884\u671F\u3002
|
|
25692
25898
|
|
|
25693
25899
|
# \u8F93\u51FA\u683C\u5F0F\uFF08\u4EC5JSON\uFF09
|
|
25694
25900
|
\u4F60\u5FC5\u987B\u4EC5\u4EE5 JSON \u683C\u5F0F\u56DE\u590D\uFF0C\u7ED3\u6784\u5982\u4E0B\uFF1A
|
|
@@ -25843,7 +26049,9 @@ ${rubricsSection}
|
|
|
25843
26049
|
pass,
|
|
25844
26050
|
final_score: finalScore,
|
|
25845
26051
|
dimension_results: dimensionResults,
|
|
25846
|
-
summary: parsedResult.summary || testResultContent
|
|
26052
|
+
summary: parsedResult.summary || testResultContent,
|
|
26053
|
+
interrupted: interrupt5 ? true : void 0,
|
|
26054
|
+
interrupt: interrupt5 ? { id: interrupt5.id, value: interrupt5.value } : void 0
|
|
25847
26055
|
};
|
|
25848
26056
|
}
|
|
25849
26057
|
};
|
|
@@ -25858,6 +26066,8 @@ async function evaluateLatticeCaseWithLogs(evalCase, config) {
|
|
|
25858
26066
|
return {
|
|
25859
26067
|
caseId: evalCase.caseId,
|
|
25860
26068
|
result,
|
|
26069
|
+
interrupted: result?.interrupted,
|
|
26070
|
+
interrupt: result?.interrupt,
|
|
25861
26071
|
duration_ms: meta.duration_ms,
|
|
25862
26072
|
thread_id: meta.thread_id,
|
|
25863
26073
|
judge_thread_id: meta.judge_thread_id,
|
|
@@ -25940,7 +26150,8 @@ function resolveTemplateCase(templateCase, templates) {
|
|
|
25940
26150
|
eval: {
|
|
25941
26151
|
content_assertion: templateCase.eval.content_assertion,
|
|
25942
26152
|
eval_rubrics: templateCase.eval.eval_rubrics || template.default_case.eval?.eval_rubrics
|
|
25943
|
-
}
|
|
26153
|
+
},
|
|
26154
|
+
interruptPolicy: templateCase.interruptPolicy ?? template.default_case.interruptPolicy
|
|
25944
26155
|
};
|
|
25945
26156
|
return resolvedCase;
|
|
25946
26157
|
}
|
|
@@ -26006,6 +26217,8 @@ var LatticeEvalSuite = class {
|
|
|
26006
26217
|
result: run.result,
|
|
26007
26218
|
error: run.error,
|
|
26008
26219
|
error_stack: run.error_stack,
|
|
26220
|
+
interrupted: run.interrupted,
|
|
26221
|
+
interrupt: run.interrupt,
|
|
26009
26222
|
duration_ms: run.duration_ms,
|
|
26010
26223
|
thread_id: run.thread_id,
|
|
26011
26224
|
judge_thread_id: run.judge_thread_id,
|
|
@@ -26038,6 +26251,8 @@ var LatticeEvalSuite = class {
|
|
|
26038
26251
|
result: run.result,
|
|
26039
26252
|
error: run.error,
|
|
26040
26253
|
error_stack: run.error_stack,
|
|
26254
|
+
interrupted: run.interrupted,
|
|
26255
|
+
interrupt: run.interrupt,
|
|
26041
26256
|
duration_ms: run.duration_ms,
|
|
26042
26257
|
thread_id: run.thread_id,
|
|
26043
26258
|
judge_thread_id: run.judge_thread_id,
|
|
@@ -26247,24 +26462,29 @@ Running batch: ${this.project.projectName} (${this.getSuiteNames().length} suite
|
|
|
26247
26462
|
let total_cases = 0;
|
|
26248
26463
|
let passed_cases = 0;
|
|
26249
26464
|
let failed_cases = 0;
|
|
26465
|
+
let interrupted_cases = 0;
|
|
26250
26466
|
const suites = [];
|
|
26251
26467
|
for (const [suiteName, caseResults] of results.entries()) {
|
|
26252
26468
|
const suiteTotal = caseResults.length;
|
|
26253
26469
|
const suitePassed = caseResults.filter((r) => r.result?.pass).length;
|
|
26470
|
+
const suiteInterrupted = caseResults.filter((r) => r.interrupted).length;
|
|
26254
26471
|
const suiteFailed = suiteTotal - suitePassed;
|
|
26255
26472
|
total_cases += suiteTotal;
|
|
26256
26473
|
passed_cases += suitePassed;
|
|
26257
26474
|
failed_cases += suiteFailed;
|
|
26475
|
+
interrupted_cases += suiteInterrupted;
|
|
26258
26476
|
suites.push({
|
|
26259
26477
|
suiteName,
|
|
26260
26478
|
total_cases: suiteTotal,
|
|
26261
26479
|
passed_cases: suitePassed,
|
|
26262
26480
|
failed_cases: suiteFailed,
|
|
26481
|
+
interrupted_cases: suiteInterrupted,
|
|
26263
26482
|
cases: caseResults.map((r) => ({
|
|
26264
26483
|
caseId: r.caseId,
|
|
26265
26484
|
pass: r.result?.pass,
|
|
26266
26485
|
final_score: r.result?.final_score,
|
|
26267
|
-
error: r.error
|
|
26486
|
+
error: r.error,
|
|
26487
|
+
interrupted: r.interrupted
|
|
26268
26488
|
}))
|
|
26269
26489
|
});
|
|
26270
26490
|
}
|
|
@@ -26282,13 +26502,14 @@ Running batch: ${this.project.projectName} (${this.getSuiteNames().length} suite
|
|
|
26282
26502
|
total_cases,
|
|
26283
26503
|
passed_cases,
|
|
26284
26504
|
failed_cases,
|
|
26505
|
+
interrupted_cases,
|
|
26285
26506
|
pass_rate: total_cases > 0 ? passed_cases / total_cases : 0
|
|
26286
26507
|
},
|
|
26287
26508
|
suites
|
|
26288
26509
|
};
|
|
26289
26510
|
console.log(`
|
|
26290
26511
|
=== Summary ===`);
|
|
26291
|
-
console.log(`Total: ${report.summary.total_cases} | Passed: ${report.summary.passed_cases} | Failed: ${report.summary.failed_cases} | Pass Rate: ${(report.summary.pass_rate * 100).toFixed(2)}%`);
|
|
26512
|
+
console.log(`Total: ${report.summary.total_cases} | Passed: ${report.summary.passed_cases} | Failed: ${report.summary.failed_cases} | Interrupted: ${report.summary.interrupted_cases} | Pass Rate: ${(report.summary.pass_rate * 100).toFixed(2)}%`);
|
|
26292
26513
|
return { batch_id, results, report };
|
|
26293
26514
|
}
|
|
26294
26515
|
};
|
|
@@ -28237,10 +28458,21 @@ Write assertions as objective, verifiable natural language:
|
|
|
28237
28458
|
- steps: [{agent_id: "a"}, {agent_id: "b", override_message: "Based on..."}] for chain
|
|
28238
28459
|
- outputType: "message_content" or "file_content"
|
|
28239
28460
|
|
|
28461
|
+
## Designing HITL Cases
|
|
28462
|
+
If the flow under test PAUSES for human input (HITL \u2014 the agent requests approval/confirmation), configure interruptPolicy on the case \u2014 otherwise the run stops at the pause and the flow AFTER the human input is never tested:
|
|
28463
|
+
|
|
28464
|
+
- interruptPolicy: {mode: "auto-approve"} \u2014 inject "\u540C\u610F"; tests the full flow after approval (e.g. payment executed after approval). Use value to override the injected text.
|
|
28465
|
+
- interruptPolicy: {mode: "auto-reject"} \u2014 inject "\u62D2\u7EDD"; tests the rejection path.
|
|
28466
|
+
- interruptPolicy: {mode: "canned-response", value: "..."} \u2014 inject an exact human reply; tests behavior under a specific response.
|
|
28467
|
+
- Omit (default "stop") \u2014 the case pauses at the request; the judge evaluates whether pausing was the correct behavior (e.g. "must request approval" PASSES; "must be autonomous" FAILS).
|
|
28468
|
+
|
|
28469
|
+
Choose per the assertion: if the assertion describes what happens AFTER the human input, you MUST set an auto-resolve policy.
|
|
28470
|
+
|
|
28240
28471
|
## Checklist
|
|
28241
28472
|
1. Check existing assets with read_eval to avoid duplication
|
|
28242
28473
|
2. Start with 3-5 high-signal cases
|
|
28243
|
-
3.
|
|
28474
|
+
3. If the flow contains a human-approval step and the assertion covers what happens AFTER it, set interruptPolicy (auto-approve / auto-reject / canned-response) \u2014 never leave it unset in that case
|
|
28475
|
+
4. Confirm with user before calling manage_eval
|
|
28244
28476
|
`,
|
|
28245
28477
|
"eval-run-and-govern": `---
|
|
28246
28478
|
name: eval-run-and-govern
|
|
@@ -28250,8 +28482,11 @@ description: Run agent evaluations, interpret results, diagnose failures, and re
|
|
|
28250
28482
|
# Agent Governance Loop
|
|
28251
28483
|
|
|
28252
28484
|
1. Discover project \u2192 read_eval list_projects
|
|
28253
|
-
2. Start evaluation \u2192 run_eval start(projectId) \u2014
|
|
28254
|
-
|
|
28485
|
+
2. Start evaluation \u2192 run_eval start(projectId) \u2014 SYNCHRONOUS by default:
|
|
28486
|
+
blocks up to ~150s and returns the FINAL RESULTS in one call.
|
|
28487
|
+
Hold-out (validation) runs return aggregates only.
|
|
28488
|
+
3. If still running (or use wait: false for fire-and-forget) \u2192 poll
|
|
28489
|
+
run_eval status(runId, sleepMs) \u2014 pass sleepMs to pace (15s, 30s, 60s, max 120s)
|
|
28255
28490
|
4. If runnerAlive=false and status=running \u2192 ORPHANED (gateway restart).
|
|
28256
28491
|
resume(runId) marks it failed automatically \u2014 then start a new run.
|
|
28257
28492
|
5. Get results \u2192 read_eval get_run_results(runId) for per-case dimension scores
|
|
@@ -28320,10 +28555,12 @@ function sanitize(obj) {
|
|
|
28320
28555
|
}
|
|
28321
28556
|
function aggregateHoldoutResults(results) {
|
|
28322
28557
|
const passed = results.filter((r) => r.pass).length;
|
|
28558
|
+
const interrupted = results.filter((r) => r.interrupted).length;
|
|
28323
28559
|
return {
|
|
28324
28560
|
holdout: true,
|
|
28325
28561
|
passedCases: passed,
|
|
28326
28562
|
failedCases: results.length - passed,
|
|
28563
|
+
interruptedCases: interrupted,
|
|
28327
28564
|
passRate: results.length > 0 ? passed / results.length : 0,
|
|
28328
28565
|
totalCases: results.length
|
|
28329
28566
|
};
|
|
@@ -28394,13 +28631,8 @@ function createReadEvalTool() {
|
|
|
28394
28631
|
if (!run) return JSON.stringify({ success: false, error: "Run not found" });
|
|
28395
28632
|
const results = await store.getResultsByRun(tid, input.runId);
|
|
28396
28633
|
if (run.holdout) {
|
|
28397
|
-
const passed = results.filter((r) => r.pass).length;
|
|
28398
28634
|
data = {
|
|
28399
|
-
|
|
28400
|
-
passedCases: passed,
|
|
28401
|
-
failedCases: results.length - passed,
|
|
28402
|
-
passRate: results.length > 0 ? passed / results.length : 0,
|
|
28403
|
-
totalCases: results.length,
|
|
28635
|
+
...aggregateHoldoutResults(results),
|
|
28404
28636
|
message: "Hold-out run \u2014 per-case results withheld. Only aggregates are available."
|
|
28405
28637
|
};
|
|
28406
28638
|
} else {
|
|
@@ -28435,6 +28667,7 @@ ACTIONS:
|
|
|
28435
28667
|
- get_run_results(runId) \u2014 per-case results with dimension scores.
|
|
28436
28668
|
For HOLD-OUT (validation-only) runs: returns AGGREGATES ONLY
|
|
28437
28669
|
(passRate, counts) \u2014 per-case details are withheld by design.
|
|
28670
|
+
Cases paused for human input (HITL) carry interrupted=true and are judged \u2014 the judge evaluates whether pausing was correct business behavior.
|
|
28438
28671
|
- get_project_report(projectId) \u2014 aggregated stats across all runs`,
|
|
28439
28672
|
schema: schema6
|
|
28440
28673
|
}
|
|
@@ -28465,7 +28698,11 @@ function createManageEvalTool() {
|
|
|
28465
28698
|
steps: z66.array(z66.object({ agent_id: z66.string(), override_message: z66.string().optional() })).optional(),
|
|
28466
28699
|
outputType: z66.enum(["file_content", "message_content"]).optional(),
|
|
28467
28700
|
contentAssertion: z66.string().optional(),
|
|
28468
|
-
rubrics: z66.array(z66.object({ name: z66.string(), weight: z66.number(), description: z66.string() })).optional()
|
|
28701
|
+
rubrics: z66.array(z66.object({ name: z66.string(), weight: z66.number(), description: z66.string() })).optional(),
|
|
28702
|
+
interruptPolicy: z66.object({
|
|
28703
|
+
mode: z66.enum(["stop", "auto-approve", "auto-reject", "canned-response"]).describe("stop=judge the pause; auto-approve/auto-reject/canned-response=resume the agent to test the flow after the human input"),
|
|
28704
|
+
value: z66.string().optional().describe("Response to inject (defaults: \u540C\u610F / \u62D2\u7EDD; required for canned-response)")
|
|
28705
|
+
}).optional().describe("Optional for create_case/update_case \u2014 how HITL interrupts are handled")
|
|
28469
28706
|
});
|
|
28470
28707
|
return tool62(
|
|
28471
28708
|
async (input, exeConfig) => {
|
|
@@ -28523,7 +28760,8 @@ function createManageEvalTool() {
|
|
|
28523
28760
|
steps: input.steps,
|
|
28524
28761
|
outputType: input.outputType,
|
|
28525
28762
|
contentAssertion: input.contentAssertion,
|
|
28526
|
-
rubrics: input.rubrics
|
|
28763
|
+
rubrics: input.rubrics,
|
|
28764
|
+
interruptPolicy: input.interruptPolicy
|
|
28527
28765
|
});
|
|
28528
28766
|
break;
|
|
28529
28767
|
case "update_case":
|
|
@@ -28531,7 +28769,8 @@ function createManageEvalTool() {
|
|
|
28531
28769
|
inputMessage: input.inputMessage,
|
|
28532
28770
|
contentAssertion: input.contentAssertion,
|
|
28533
28771
|
steps: input.steps,
|
|
28534
|
-
rubrics: input.rubrics
|
|
28772
|
+
rubrics: input.rubrics,
|
|
28773
|
+
interruptPolicy: input.interruptPolicy
|
|
28535
28774
|
});
|
|
28536
28775
|
break;
|
|
28537
28776
|
case "delete_case":
|
|
@@ -28556,9 +28795,13 @@ Project: create_project(name, description?, judgeModelKey?, concurrency?) | upda
|
|
|
28556
28795
|
**When creating a project from within a workspace, the workspace/project context is
|
|
28557
28796
|
automatically bound \u2014 eval runs will execute in the same workspace.**
|
|
28558
28797
|
Suite: create_suite(projectId, name) | update_suite | delete_suite
|
|
28559
|
-
Case: create_case(suiteId, inputMessage, steps, outputType, contentAssertion, inputFiles?, rubrics?)
|
|
28798
|
+
Case: create_case(suiteId, inputMessage, steps, outputType, contentAssertion, inputFiles?, rubrics?, interruptPolicy?)
|
|
28560
28799
|
steps is [{agent_id, override_message?}]. outputType is "file_content" or "message_content".
|
|
28561
|
-
rubrics is [{name, weight, description}]. | update_case | delete_case
|
|
28800
|
+
rubrics is [{name, weight, description}]. | update_case | delete_case
|
|
28801
|
+
interruptPolicy: {mode: "stop"|"auto-approve"|"auto-reject"|"canned-response", value?} \u2014 how HITL interrupts are handled:
|
|
28802
|
+
stop (default): case pauses at the human-input request; the judge evaluates the pause as business behavior.
|
|
28803
|
+
auto-approve / auto-reject: the runner injects approval/rejection and tests the FULL flow after the pause.
|
|
28804
|
+
canned-response: injects the exact value (simulates a specific human reply).`,
|
|
28562
28805
|
schema: schema6
|
|
28563
28806
|
}
|
|
28564
28807
|
);
|
|
@@ -28672,6 +28915,8 @@ ACTIONS:
|
|
|
28672
28915
|
- start(projectId, suiteIds?, caseIds?, wait?) \u2014 begin evaluation (optionally only the listed suites, and/or only the listed cases).
|
|
28673
28916
|
wait=true (DEFAULT): SYNCHRONOUS \u2014 blocks up to ~150s and returns the FINAL RESULTS in one call:
|
|
28674
28917
|
{ status, results } with per-case pass/score (hold-out/validation runs: aggregates only \u2014 per-case details withheld by design).
|
|
28918
|
+
Cases paused for human input (HITL) carry interrupted=true and ARE judged \u2014 the judge evaluates whether requesting
|
|
28919
|
+
the human was the correct behavior (assertions like "must approve first" PASS; "must be autonomous" FAIL). interruptedCases counts these.
|
|
28675
28920
|
If the run exceeds 150s: returns { runId, status: "running" } \u2014 NOT an error \u2014 then poll with status/resume until completed.
|
|
28676
28921
|
wait=false: fire-and-forget \u2014 returns { runId } immediately; poll with status.
|
|
28677
28922
|
- status(runId, sleepMs?) \u2014 sleep sleepMs first (to pace polling), then return current status + runnerAlive flag:
|
|
@@ -28977,67 +29222,64 @@ verification choice, then start benchmarking.
|
|
|
28977
29222
|
|
|
28978
29223
|
## Task Tracking \u2014 see [[task-tracking]]
|
|
28979
29224
|
|
|
28980
|
-
**
|
|
28981
|
-
|
|
28982
|
-
|
|
28983
|
-
|
|
28984
|
-
|
|
28985
|
-
|
|
28986
|
-
|
|
28987
|
-
never mark a subtask completed while eval
|
|
28988
|
-
runs with manage_task list.
|
|
29225
|
+
**Universal principle**: once the goal is clear and you know what to
|
|
29226
|
+
do, create the parent task BEFORE executing (manage_task create, see
|
|
29227
|
+
[[task-tracking]]). In this workflow: after Phase 0 clarification
|
|
29228
|
+
completes and the user confirmed the path (end of 0.5), create the
|
|
29229
|
+
parent task; then a subtask per phase as you start it. The parent task
|
|
29230
|
+
description carries the GOAL MODEL (0.1.5) as Objective + Acceptance
|
|
29231
|
+
Criteria; the expected output spec (2.6) updates the criteria. Update
|
|
29232
|
+
status to reflect reality \u2014 never mark a subtask completed while eval
|
|
29233
|
+
fails. Resume interrupted runs with manage_task list.
|
|
28989
29234
|
|
|
28990
29235
|
Widgets: call \`load_guidelines\` ONCE before your first \`show_widget\`
|
|
28991
29236
|
(show_widget hard-requires it), then reuse.
|
|
28992
29237
|
|
|
28993
29238
|
---
|
|
28994
29239
|
|
|
28995
|
-
## Phase 1:
|
|
28996
|
-
|
|
28997
|
-
The
|
|
28998
|
-
|
|
28999
|
-
|
|
29000
|
-
|
|
29001
|
-
|
|
29002
|
-
|
|
29003
|
-
|
|
29004
|
-
|
|
29005
|
-
|
|
29006
|
-
|
|
29007
|
-
|
|
29008
|
-
|
|
29009
|
-
|
|
29010
|
-
|
|
29011
|
-
|
|
29012
|
-
|
|
29013
|
-
|
|
29014
|
-
|
|
29015
|
-
|
|
29016
|
-
the
|
|
29017
|
-
- **
|
|
29018
|
-
|
|
29019
|
-
|
|
29020
|
-
|
|
29021
|
-
|
|
29022
|
-
|
|
29023
|
-
|
|
29024
|
-
|
|
29025
|
-
|
|
29026
|
-
|
|
29027
|
-
|
|
29028
|
-
|
|
29029
|
-
|
|
29030
|
-
|
|
29031
|
-
|
|
29032
|
-
|
|
29033
|
-
|
|
29034
|
-
|
|
29035
|
-
|
|
29036
|
-
|
|
29037
|
-
|
|
29038
|
-
discover existing agents with relevant capabilities (see \xA75).
|
|
29039
|
-
For \u2460, look for agents with data-access tools (SQL / API). For \u2461, look
|
|
29040
|
-
for agents with independence.
|
|
29240
|
+
## Phase 1: Explore (goal-driven path finding)
|
|
29241
|
+
|
|
29242
|
+
The goal model (0.1.5) is set. Now EXPLORE how to achieve it \u2014 actively
|
|
29243
|
+
hunt for the path, do not passively read. Three exploration fronts:
|
|
29244
|
+
|
|
29245
|
+
**A. Existing assets (reuse, don't rebuild):**
|
|
29246
|
+
- \`list_agents\` / \`load_skills\` \u2192 are there existing agents or skills
|
|
29247
|
+
that already do part of this? Reuse them (update_agent if needed)
|
|
29248
|
+
instead of building from scratch. This is a goal-relevant check, not
|
|
29249
|
+
a materials step.
|
|
29250
|
+
- \`list_tools\` / \`list_middleware_types\` \u2192 what capabilities exist
|
|
29251
|
+
that the goal needs (parsing, data access, browser...)?
|
|
29252
|
+
- \`list_connections\` \u2192 are the data sources the goal depends on
|
|
29253
|
+
already connected?
|
|
29254
|
+
- If verification will happen (0.2 \u2460 or \u2461): concurrently discover
|
|
29255
|
+
executor candidates (see \xA75). \u2460 \u2192 data-access tools; \u2461 \u2192 independence.
|
|
29256
|
+
|
|
29257
|
+
**B. Material probing (by material type):**
|
|
29258
|
+
- **User-description**: the requirements come from the conversation.
|
|
29259
|
+
Extract goal, inputs, outputs, constraints \u2014 then explore the
|
|
29260
|
+
implementation path (A + feasibility): what assets exist, what tools
|
|
29261
|
+
are needed, what blockers stand between the goal and its achievement.
|
|
29262
|
+
- **Document** (PDF / spec / manual): benchmark engines as needed \u2014
|
|
29263
|
+
parse directly with the chosen engine (0.3 \u2460-\u2464) or run
|
|
29264
|
+
document-parser-benchmark. Engine selection IS distilled knowledge:
|
|
29265
|
+
it builds the agent (engine's parse_document into middleware), seeds
|
|
29266
|
+
the skill (feature signature + winning engine), and designs the tests
|
|
29267
|
+
(engine output as case baseline input).
|
|
29268
|
+
- **API spec**: read directly \u2014 endpoints, schemas, examples.
|
|
29269
|
+
- **Conversation**: extract workflow, decisions, corrections.
|
|
29270
|
+
- **Spreadsheet**: parse cells directly.
|
|
29271
|
+
|
|
29272
|
+
**C. Feasibility (path blockers):**
|
|
29273
|
+
- What stands between the goal and achievement? Missing tools, missing
|
|
29274
|
+
connections, data access, permission constraints, ambiguous
|
|
29275
|
+
requirements.
|
|
29276
|
+
- Does the goal require orchestration (\u2192 Phase 2 split decision)?
|
|
29277
|
+
- Surface these in the recommendation (Phase 1.5) \u2014 the user decides
|
|
29278
|
+
the path, informed by what exploration found.
|
|
29279
|
+
|
|
29280
|
+
Exploration is COMPLETE when you can answer: what exists to reuse,
|
|
29281
|
+
what must be built, what tools/connections are needed, and what blocks
|
|
29282
|
+
the goal. Do not go to design without this map.
|
|
29041
29283
|
|
|
29042
29284
|
---
|
|
29043
29285
|
|
|
@@ -29052,17 +29294,21 @@ candidate and assess (Validation Agent Design \xA70) \u2014 state which are
|
|
|
29052
29294
|
usable and which are not, with reasons. For \u2460, the executor needs data
|
|
29053
29295
|
tools + independence. For \u2461, independence only. If no candidate fits,
|
|
29054
29296
|
plan to build one via \xA75.
|
|
29055
|
-
Present
|
|
29297
|
+
Present the EXPLORATION map as widget \u2014 what exists to reuse, what
|
|
29298
|
+
must be built, tools/connections needed, blockers found \u2014 then
|
|
29299
|
+
recommend the IMPLEMENTATION PATH: reuse existing X, build new Y,
|
|
29300
|
+
split or single agent (Phase 2 input). MUST call
|
|
29056
29301
|
\`ask_user_to_clarify\` NOW:
|
|
29057
29302
|
{
|
|
29058
29303
|
"questions": [{
|
|
29059
|
-
"question": "Confirm the
|
|
29304
|
+
"question": "Confirm the recommended path?",
|
|
29060
29305
|
"options": ["Confirm", "Adjust"],
|
|
29061
29306
|
"type": "single",
|
|
29062
29307
|
"required": true
|
|
29063
29308
|
}]
|
|
29064
29309
|
}
|
|
29065
|
-
Skills planning belongs to Phase 2 \u2014 this phase presents
|
|
29310
|
+
Skills planning belongs to Phase 2 \u2014 this phase presents the path, not
|
|
29311
|
+
the detailed plan.
|
|
29066
29312
|
|
|
29067
29313
|
---
|
|
29068
29314
|
|
|
@@ -29130,9 +29376,53 @@ user-description material this IS the core phase; for material-based
|
|
|
29130
29376
|
learning it designs the agent that runs the learned skill. Agent
|
|
29131
29377
|
metadata (verified/version/source) must be set on creation.
|
|
29132
29378
|
|
|
29379
|
+
## Phase 2.6: Expected Output Specification (mandatory \u2014 goal-driven)
|
|
29380
|
+
|
|
29381
|
+
**Expectations come FIRST, before writing the skill.** You cannot write
|
|
29382
|
+
a skill (or test cases) without a target. Define the expected output
|
|
29383
|
+
specification from the goal model (0.1.5: real goal / consumer / usable
|
|
29384
|
+
state) BEFORE Phase 3:
|
|
29385
|
+
|
|
29386
|
+
**HARD RULE \u2014 never guess the target.** If the goal, the expected
|
|
29387
|
+
output, the consumer, or the usable state is unclear at ANY point
|
|
29388
|
+
before writing test cases, you MUST ask the user via
|
|
29389
|
+
\`ask_user_to_clarify\` \u2014 do NOT proceed with an assumed expectation.
|
|
29390
|
+
A test case written against a guessed expectation is worthless: it
|
|
29391
|
+
validates the wrong thing. When in doubt, ask.
|
|
29392
|
+
|
|
29393
|
+
Per skill, define the EXPECTED OUTPUT SPEC (based on intent 0.1 and
|
|
29394
|
+
consumer 0.1.5):
|
|
29395
|
+
- Extract data \u2192 expected fields (names, types, formats), required vs
|
|
29396
|
+
optional, output structure (JSON schema shape, table columns)
|
|
29397
|
+
- Validate rules \u2192 expected judgment outcomes (pass/fail conditions),
|
|
29398
|
+
boundary values, and the reason format
|
|
29399
|
+
- Execute workflow \u2192 expected step sequence, decision points, final
|
|
29400
|
+
outcome shape
|
|
29401
|
+
- Answer knowledge \u2192 expected answer form (with/without sources,
|
|
29402
|
+
length, structure)
|
|
29403
|
+
|
|
29404
|
+
This spec IS the acceptance standard. Phase 4 contentAssertion must be
|
|
29405
|
+
derived from it (not invented at case-writing time). Present the
|
|
29406
|
+
expected output spec to the user and MUST call \`ask_user_to_clarify\`
|
|
29407
|
+
NOW per skill:
|
|
29408
|
+
{
|
|
29409
|
+
"questions": [{
|
|
29410
|
+
"question": "Confirm the expected output spec for {skill-name}?",
|
|
29411
|
+
"options": ["Confirm", "Adjust"],
|
|
29412
|
+
"type": "single",
|
|
29413
|
+
"required": true,
|
|
29414
|
+
"allowOther": true
|
|
29415
|
+
}]
|
|
29416
|
+
}
|
|
29417
|
+
Record the confirmed spec in the parent task description. This replaces
|
|
29418
|
+
guess-then-confirm: the skill is written TO MEET the spec, and test
|
|
29419
|
+
cases assert AGAINST the spec \u2014 no expectation is invented later.
|
|
29420
|
+
|
|
29133
29421
|
## Phase 3: Create Skills
|
|
29134
29422
|
|
|
29135
|
-
Write SKILL.md to \`/root/.agents/skills/{name}/SKILL.md\` one at a time
|
|
29423
|
+
Write SKILL.md to \`/root/.agents/skills/{name}/SKILL.md\` one at a time,
|
|
29424
|
+
designed TO MEET the expected output spec confirmed in Phase 2.6 \u2014 the
|
|
29425
|
+
skill encodes how to produce the spec's expected output.
|
|
29136
29426
|
Show the skill content in text first, then MUST call
|
|
29137
29427
|
\`ask_user_to_clarify\` NOW per skill:
|
|
29138
29428
|
{
|
|
@@ -29426,7 +29716,8 @@ This learning loop adds its own scenario rules:
|
|
|
29426
29716
|
- Business usability (output reaches the goal's "usable state")
|
|
29427
29717
|
- Consumer fit (format/contract satisfies who uses the result)
|
|
29428
29718
|
contentAssertion must encode the usable state from the goal model
|
|
29429
|
-
(0.1.5),
|
|
29719
|
+
(0.1.5), derived from the EXPECTED OUTPUT SPEC (Phase 2.6) \u2014 never
|
|
29720
|
+
invented at case-writing time.
|
|
29430
29721
|
|
|
29431
29722
|
1. One suite per skill per source: cases test "can this skill do it" \u2014
|
|
29432
29723
|
never mix skills in one suite
|
|
@@ -29469,6 +29760,12 @@ Learning-specific suite guidance:
|
|
|
29469
29760
|
- User-description material: {skill}-requirement-derived \u2014 cases from
|
|
29470
29761
|
user's described requirements
|
|
29471
29762
|
|
|
29763
|
+
**Case expectations come from the confirmed spec** (Phase 2.6): the
|
|
29764
|
+
contentAssertion of every case must be derived from the expected output
|
|
29765
|
+
spec, NOT invented at case-writing time. If a case needs an expectation
|
|
29766
|
+
not in the spec, go back and extend the spec with user confirmation
|
|
29767
|
+
first \u2014 never guess expectations on the fly.
|
|
29768
|
+
|
|
29472
29769
|
[[completion-gate]] applies \u2014 eval must pass before declaring done.
|
|
29473
29770
|
|
|
29474
29771
|
## Phase 5: Retrospective
|