@axiom-lattice/core 3.0.4 → 3.0.6
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 +906 -350
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +774 -219
- 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,30 @@ 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
|
+
|
|
10792
|
+
## Knowledge in Skills (apply to EVERY sub-skill workflow)
|
|
10793
|
+
|
|
10794
|
+
**Domain knowledge lives in SKILL.md files, not in prompts.** The
|
|
10795
|
+
deliverable's knowledge (rules, formats, decision logic, procedures) is
|
|
10796
|
+
authored as skills; the executable (agent prompt, workflow step) stays
|
|
10797
|
+
THIN \u2014 role/process only, loading knowledge via "Load [[skill-name]]
|
|
10798
|
+
and follow it". Never write domain knowledge directly into a system
|
|
10799
|
+
prompt or a workflow step's prompt.
|
|
10800
|
+
|
|
10801
|
+
Why: knowledge in prompts cannot be reused, individually verified, or
|
|
10802
|
+
evolved. Knowledge in skills is shared (subSkills), regression-tested
|
|
10803
|
+
([[eval-verify]]), and improved without touching the executable.
|
|
10804
|
+
|
|
10805
|
+
Applies to every construction path: [[learn-capability]] (skills are
|
|
10806
|
+
the primary output), [[agent-build]] (agent prompt thin, loads skill),
|
|
10807
|
+
[[design-workflow]] (steps reference [[skill-name]] or ref to
|
|
10808
|
+
skill-loading agents). All three follow this single principle.
|
|
10809
|
+
|
|
10720
10810
|
## Goal-Driven Validation (apply to EVERY sub-skill workflow)
|
|
10721
10811
|
|
|
10722
10812
|
The agent evaluates goal achievement ITSELF via multi-dimensional test
|
|
@@ -10736,6 +10826,29 @@ green = goal achieved (per [[completion-gate]] and [[eval-verify]]).
|
|
|
10736
10826
|
The goal model is the acceptance standard \u2014 contentAssertion must
|
|
10737
10827
|
encode the usable state, not just technical correctness.
|
|
10738
10828
|
|
|
10829
|
+
## Undefined Tasks (outside the skill map)
|
|
10830
|
+
|
|
10831
|
+
If the request does not match any sub-skill workflow: do NOT guess, do
|
|
10832
|
+
NOT refuse, do NOT force-fit an existing flow. Follow the
|
|
10833
|
+
EXPLORE \u2192 PROPOSE \u2192 CONFIRM protocol:
|
|
10834
|
+
|
|
10835
|
+
1. **Explore** \u2014 inventory before proposing anything:
|
|
10836
|
+
\`list_agents\` / \`load_skills\` (existing assets), \`list_tools\` /
|
|
10837
|
+
\`list_middleware_types\` (capabilities), \`list_connections\`
|
|
10838
|
+
(data sources), eval projects (verification), docs at hand.
|
|
10839
|
+
Goal: know what is reusable and what is missing.
|
|
10840
|
+
2. **Propose** \u2014 present 2-3 concrete options, each with: what it
|
|
10841
|
+
does, cost, risk, and what it needs (new tools / new skills /
|
|
10842
|
+
approvals).
|
|
10843
|
+
3. **Confirm** \u2014 the user picks an option or adjusts it. Never
|
|
10844
|
+
execute without a chosen option.
|
|
10845
|
+
4. **New capability needed?** (new tool type, new skill, new
|
|
10846
|
+
connection) \u2014 include creating it ([[create-skill]] / connection
|
|
10847
|
+
setup) IN the proposed option; never silently proceed without it.
|
|
10848
|
+
5. **Boundary honesty** \u2014 state clearly what the architect cannot do
|
|
10849
|
+
(e.g. deploy to production, monitor runtime, change frontend),
|
|
10850
|
+
and give the alternative \u2014 never overpromise or silently refuse.
|
|
10851
|
+
|
|
10739
10852
|
## Skill Map
|
|
10740
10853
|
- [[learn-capability]] \u2014 Learn from any source material (user
|
|
10741
10854
|
description, documents, API specs, conversations, spreadsheets) and
|
|
@@ -10802,16 +10915,29 @@ Do NOT use reviewer as:
|
|
|
10802
10915
|
verification. If findings show config errors, fix and re-check.`,
|
|
10803
10916
|
"task-tracking": `---
|
|
10804
10917
|
name: task-tracking
|
|
10805
|
-
description: Manage persistent tasks
|
|
10806
|
-
|
|
10807
|
-
|
|
10918
|
+
description: Manage persistent tasks with manage_task. Universal rule:
|
|
10919
|
+
once the goal is clear and you know what to do, create the task FIRST
|
|
10920
|
+
then execute. Track parent/subtasks, update status to reflect reality,
|
|
10921
|
+
resume interrupted work. Applies to ANY multi-step agent work \u2014 not
|
|
10922
|
+
just agent building.
|
|
10808
10923
|
metadata:
|
|
10809
10924
|
domain: agent-building
|
|
10810
10925
|
verified: unverified
|
|
10811
10926
|
---
|
|
10812
10927
|
# Task Tracking \u2014 manage_task for Agent Workflows
|
|
10813
10928
|
|
|
10814
|
-
|
|
10929
|
+
**Task management is the ongoing record of a goal and its acceptance
|
|
10930
|
+
criteria** \u2014 it answers at any moment: what are we achieving, and what
|
|
10931
|
+
does "done" look like. Create a task when the goal is clear; keep its
|
|
10932
|
+
Objective and Acceptance Criteria current as work proceeds; change
|
|
10933
|
+
status only when the criteria are actually met.
|
|
10934
|
+
|
|
10935
|
+
**Universal principle**: whenever the goal is understood and the work
|
|
10936
|
+
is about to start, create a task BEFORE executing. If you can write an
|
|
10937
|
+
Objective and Acceptance Criteria, it deserves a task. This is not
|
|
10938
|
+
optional and not limited to agent-building \u2014 it applies to any
|
|
10939
|
+
multi-step work (learning, building, modifying skills, fixing, anything
|
|
10940
|
+
with a clear goal).
|
|
10815
10941
|
|
|
10816
10942
|
## When to create (and when NOT)
|
|
10817
10943
|
|
|
@@ -10828,13 +10954,32 @@ Do NOT create tasks for:
|
|
|
10828
10954
|
|
|
10829
10955
|
## Setup
|
|
10830
10956
|
|
|
10957
|
+
**A task is a living record of the GOAL + ACCEPTANCE CRITERIA** \u2014 not a
|
|
10958
|
+
todo label. Every task's description must carry:
|
|
10959
|
+
|
|
10960
|
+
- **Goal Model** \u2014 the full goal model ([[agent-architecture|Goal
|
|
10961
|
+
Model]]): real goal, consumer (who uses the result), usable state
|
|
10962
|
+
(what "done and usable" means concretely)
|
|
10963
|
+
- **Objective** \u2014 one measurable sentence: what result to achieve
|
|
10964
|
+
- **Acceptance Criteria** \u2014 checkboxes that define "done": when ALL
|
|
10965
|
+
are checked, the task is verifiably complete
|
|
10966
|
+
|
|
10967
|
+
The task is created when the goal is confirmed, and its description is
|
|
10968
|
+
CONTINUALLY UPDATED as the work progresses (spec evolves, criteria are
|
|
10969
|
+
met, new criteria emerge). Status changes only when the criteria are
|
|
10970
|
+
truly met \u2014 never as a workaround.
|
|
10971
|
+
|
|
10831
10972
|
- **Create the parent task when the scope is confirmed** \u2014 before
|
|
10832
10973
|
starting the first real work phase (probe/design/build):
|
|
10833
|
-
\`manage_task create(title: <goal>, description: <
|
|
10974
|
+
\`manage_task create(title: <goal>, description: <Objective + Acceptance Criteria>, ownerType: "agent")\`
|
|
10834
10975
|
Record the returned parent task id.
|
|
10835
10976
|
- **Create a subtask per phase** as you start each phase (probe /
|
|
10836
10977
|
design / build / eval / retro):
|
|
10837
|
-
\`manage_task create(title: <phase>, parentId: <parent>, ownerType: "agent")\`
|
|
10978
|
+
\`manage_task create(title: <phase>, description: <Objective + Acceptance Criteria>, parentId: <parent>, ownerType: "agent")\`
|
|
10979
|
+
- **Update the description as work proceeds**: append progress, mark
|
|
10980
|
+
criteria \`[x]\`, revise criteria when the goal model/spec changes.
|
|
10981
|
+
The task tracks the target and its acceptance \u2014 read it to know what
|
|
10982
|
+
"done" means, keep it current so it always reflects reality.
|
|
10838
10983
|
|
|
10839
10984
|
## Status discipline \u2014 MANDATORY
|
|
10840
10985
|
|
|
@@ -10965,8 +11110,13 @@ When unsure, use \`show_widget\` for visual comparison.
|
|
|
10965
11110
|
- **Follow [[agent-architecture|Goal Model]]** \u2014 establish the goal
|
|
10966
11111
|
model (real goal / consumer / usable state) and design the agent to
|
|
10967
11112
|
achieve it; verification is goal-driven ([[agent-architecture|Goal-Driven Validation]]).
|
|
10968
|
-
- **
|
|
10969
|
-
|
|
11113
|
+
- **Follow [[agent-architecture|Knowledge in Skills]]** \u2014 the prompt is
|
|
11114
|
+
thin (role/behavior); domain knowledge lives in SKILL.md which the
|
|
11115
|
+
agent loads ("Load [[skill-name]] and follow it"). Never write
|
|
11116
|
+
domain knowledge directly into a system prompt.
|
|
11117
|
+
- **NEVER build before confirming.** Design \u2192 confirm via
|
|
11118
|
+
\`ask_user_to_clarify\` \u2192 wait for approval \u2192 only then build.
|
|
11119
|
+
No exceptions.
|
|
10970
11120
|
- **Track with tasks once scope is clear.** After requirements are
|
|
10971
11121
|
clarified, create the parent task ([[task-tracking]]) before starting
|
|
10972
11122
|
design. Don't create tasks during clarification.
|
|
@@ -10979,18 +11129,23 @@ When unsure, use \`show_widget\` for visual comparison.
|
|
|
10979
11129
|
|
|
10980
11130
|
## REACT design steps
|
|
10981
11131
|
|
|
10982
|
-
1.
|
|
11132
|
+
1. **Establish the goal model FIRST** \u2014 real goal / user expectation /
|
|
11133
|
+
consumer / usable state ([[agent-architecture|Goal Model]]); record
|
|
11134
|
+
it in the parent task. Design, build, and verification all derive
|
|
11135
|
+
from it. Only then:
|
|
10983
11136
|
2. Choose middleware \u2014 call \`list_tools\` and \`list_middleware_types\`
|
|
10984
11137
|
first. MUST include \`ask_user_to_clarify\` if the agent needs
|
|
10985
11138
|
confirmation or clarifying questions.
|
|
10986
11139
|
3. Write the system prompt: role \u2192 workflow \u2192 constraints
|
|
10987
11140
|
4. Present the design with \`show_widget\`
|
|
10988
|
-
5.
|
|
11141
|
+
5. Confirm via \`ask_user_to_clarify\` \u2014 do NOT build until approved
|
|
10989
11142
|
6. Build with \`create_agent\`
|
|
10990
11143
|
|
|
10991
11144
|
## DEEP_AGENT design steps
|
|
10992
11145
|
|
|
10993
|
-
1.
|
|
11146
|
+
1. **Establish the goal model FIRST** \u2014 real goal / consumer / usable
|
|
11147
|
+
state, recorded in the parent task ([[agent-architecture|Goal
|
|
11148
|
+
Model]]); then explain why DEEP_AGENT is the right choice
|
|
10994
11149
|
2. Capability mapping with \`show_widget\`
|
|
10995
11150
|
3. System prompt emphasizes dynamic todo workflow (analyze \u2192 break
|
|
10996
11151
|
into todos \u2192 work one at a time \u2192 refine). Middleware: code_eval,
|
|
@@ -11142,6 +11297,9 @@ description: Run agent evaluations, interpret results, fix failures, and
|
|
|
11142
11297
|
metadata:
|
|
11143
11298
|
domain: agent-building
|
|
11144
11299
|
verified: unverified
|
|
11300
|
+
subSkills:
|
|
11301
|
+
- eval-design-tests
|
|
11302
|
+
- eval-run-and-govern
|
|
11145
11303
|
---
|
|
11146
11304
|
# Eval Verify \u2014 Run Evaluations and Upgrade Trust
|
|
11147
11305
|
|
|
@@ -11158,6 +11316,13 @@ verified: unverified
|
|
|
11158
11316
|
parent (eval-{parent-id}) \u2014 see Layered verification below.
|
|
11159
11317
|
2. \`manage_eval create_case(suiteId, ...)\` per sample or scenario
|
|
11160
11318
|
Required: inputMessage, steps=[{agent_id}], outputType, contentAssertion
|
|
11319
|
+
**contentAssertion MUST come from the confirmed expected output spec**
|
|
11320
|
+
(learn-capability Phase 2.6) \u2014 never invent expectations at
|
|
11321
|
+
case-writing time. If a needed expectation is not in the spec, extend
|
|
11322
|
+
the spec with user confirmation first.
|
|
11323
|
+
**HARD RULE**: if the target/expected output is unclear at this
|
|
11324
|
+
point, STOP and ask the user (ask_user_to_clarify) \u2014 do not write a
|
|
11325
|
+
case with a guessed expectation.
|
|
11161
11326
|
|
|
11162
11327
|
## Suites per skill, by source
|
|
11163
11328
|
|
|
@@ -11167,22 +11332,70 @@ verified: unverified
|
|
|
11167
11332
|
(hold-out, never run during fix loop)
|
|
11168
11333
|
- 0.2 \u2460 \u2192 {skill}-api-verified \u2014 queryability assertion, single step
|
|
11169
11334
|
|
|
11170
|
-
## Layered verification (orchestrator +
|
|
11171
|
-
|
|
11172
|
-
When the design
|
|
11173
|
-
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11335
|
+
## Layered verification (orchestrator + components)
|
|
11336
|
+
|
|
11337
|
+
When the design delegates to other agents, verification is layered.
|
|
11338
|
+
"Orchestrator" = a parent deep_agent with subAgents (learn-capability
|
|
11339
|
+
Phase 2) OR a workflow with \`ref\` steps ([[design-workflow]]).
|
|
11340
|
+
"Components" = the subAgents / ref'd agents it calls. Order is MANDATORY:
|
|
11341
|
+
**component evals first, integration second** \u2014 never run the
|
|
11342
|
+
integration eval before every component eval passes.
|
|
11343
|
+
|
|
11344
|
+
- **Each component**: its OWN eval project (eval-{sub-agent-id} /
|
|
11345
|
+
eval-{ref-agent-id}) \u2014 the sub capability is verified independently,
|
|
11346
|
+
with its own fix loop.
|
|
11347
|
+
- **The orchestrator**: an integration eval project (eval-{parent-id} /
|
|
11348
|
+
eval-{workflow-id}). Integration cases: full end-to-end task input \u2192
|
|
11349
|
+
orchestrator invokes components \u2192 final aggregated output \u2192
|
|
11350
|
+
contentAssertion on the final result. This verifies ORCHESTRATION
|
|
11351
|
+
(does the orchestrator call the right components in the right order
|
|
11352
|
+
and aggregate correctly).
|
|
11353
|
+
- **Workflow integration cases** also include branch paths and \`ask\`
|
|
11354
|
+
handling (see Workflow testing below) \u2014 but only AFTER the ref'd
|
|
11355
|
+
agents are independently verified.
|
|
11356
|
+
- **Orchestrator trust upgrade** requires BOTH: all component evals pass
|
|
11357
|
+
AND the orchestrator's integration eval passes. The orchestrator's
|
|
11358
|
+
metadata (verified/source) records this dependency.
|
|
11359
|
+
- Independent agents (no parent, no ref) keep single-level eval \u2014 no
|
|
11360
|
+
integration layer needed.
|
|
11361
|
+
|
|
11362
|
+
## Workflow testing (WORKFLOW-type agents)
|
|
11363
|
+
|
|
11364
|
+
Workflows compile to the same agent registry and run through the same
|
|
11365
|
+
eval path \u2014 same project naming (eval-{agent-id}), same case structure
|
|
11366
|
+
(inputMessage + steps + contentAssertion). Design differs because the
|
|
11367
|
+
pipeline is DETERMINISTIC:
|
|
11368
|
+
|
|
11369
|
+
- **One case per branch path** \u2014 each if/map/parallel route gets a case
|
|
11370
|
+
whose inputMessage drives it down that path; contentAssertion = the
|
|
11371
|
+
exact output that path must produce (from the expected output spec,
|
|
11372
|
+
Phase 1.5 in [[design-workflow]]).
|
|
11373
|
+
- **Goal-driven dimensions** \u2014 cases cover all four dimensions
|
|
11374
|
+
([[agent-architecture|Goal-Driven Validation]]), not just happy paths:
|
|
11375
|
+
- Functional correctness \u2014 each branch path produces the right result
|
|
11376
|
+
- Edge robustness \u2014 empty input, if-condition not met, map source
|
|
11377
|
+
empty, malformed data: the pipeline must fail gracefully or take
|
|
11378
|
+
the designed fallback, not crash
|
|
11379
|
+
- Business usability \u2014 output reaches the usable state (usable-state
|
|
11380
|
+
cases come from the confirmed spec, never invented)
|
|
11381
|
+
- Consumer fit \u2014 exact fields/format for system consumers, readable
|
|
11382
|
+
for human consumers
|
|
11383
|
+
- **Data contract cases** \u2014 intermediate \`{{refs}}\` handoffs and
|
|
11384
|
+
\`map\` source shapes are contracts; a contract broken mid-pipeline
|
|
11385
|
+
only surfaces at the end. One case per non-trivial handoff asserting
|
|
11386
|
+
the intermediate output shape (source data + step output).
|
|
11387
|
+
- **\`ask\` steps** \u2014 case interruptPolicy controls them
|
|
11388
|
+
(mode: stop | auto-approve | auto-reject | canned-response):
|
|
11389
|
+
- \`stop\` \u2192 the run pauses at the ask; assert the partial output
|
|
11390
|
+
BEFORE the interaction point
|
|
11391
|
+
- auto-approve / auto-reject / canned-response \u2192 supply the response
|
|
11392
|
+
and continue; assert the flow AFTER the interaction point
|
|
11393
|
+
- \`value\` holds the response text (defaults "\u540C\u610F"/"\u62D2\u7EDD" for
|
|
11394
|
+
approve/reject)
|
|
11395
|
+
- **Exact assertions** \u2014 deterministic pipeline means expected outputs
|
|
11396
|
+
are precise; judge still scores semantics on top.
|
|
11397
|
+
- **Trust upgrade is the same gate** \u2014 [[completion-gate]] applies to
|
|
11398
|
+
workflows: no eval \u2192 stays configured, never verified.
|
|
11186
11399
|
|
|
11187
11400
|
## Run
|
|
11188
11401
|
|
|
@@ -11248,11 +11461,39 @@ verified: unverified
|
|
|
11248
11461
|
# Design Workflow \u2014 WORKFLOW Agent Design
|
|
11249
11462
|
|
|
11250
11463
|
Use the WORKFLOW type when the process is fully known \u2014 a deterministic
|
|
11251
|
-
state machine with pre-defined paths.
|
|
11464
|
+
state machine with pre-defined paths. If the process is NOT fully known
|
|
11465
|
+
(open-ended, needs dynamic decomposition) \u2192 use [[learn-capability]] /
|
|
11466
|
+
[[agent-build]] (REACT / DEEP_AGENT) instead.
|
|
11252
11467
|
Follow [[agent-architecture|User Interaction Rules]] and
|
|
11253
11468
|
[[agent-architecture|Goal Model]] \u2014 establish the goal model (real
|
|
11254
11469
|
goal / consumer / usable state) before designing, and design steps
|
|
11255
11470
|
that achieve it. Acceptance = workflow outcome meets the usable state.
|
|
11471
|
+
Follow [[agent-architecture|Knowledge in Skills]]: workflow steps
|
|
11472
|
+
orchestrate; domain knowledge lives in SKILL.md. Never write domain
|
|
11473
|
+
knowledge directly into a step's prompt \u2014 load it via [[skill-name]]
|
|
11474
|
+
or delegate to an agent that loads the skill.
|
|
11475
|
+
|
|
11476
|
+
## CRITICAL RULES
|
|
11477
|
+
- **NEVER build before confirming.** Design \u2192 present the flow as a
|
|
11478
|
+
widget \u2192 discuss step-by-step with the user \u2192 confirm via
|
|
11479
|
+
\`ask_user_to_clarify\` (blocking approval) \u2192 only then call
|
|
11480
|
+
\`create_workflow\`. No exceptions.
|
|
11481
|
+
- **Always visualize the design** \u2014 present with \`show_widget\` as a
|
|
11482
|
+
Flowchart (every step, branch, \`ask\` interaction point) \u2014 never a
|
|
11483
|
+
bare text list (see Visual communication below).
|
|
11484
|
+
- **One decision at a time.** Each message asks exactly one question.
|
|
11485
|
+
- **Track with tasks once scope is clear.** Create the parent task
|
|
11486
|
+
([[task-tracking]]) before designing; record the expected output spec
|
|
11487
|
+
(Phase 1.5) in it.
|
|
11488
|
+
|
|
11489
|
+
## Visual communication
|
|
11490
|
+
|
|
11491
|
+
Use \`show_widget\` for all structure explanations \u2014 never ASCII art.
|
|
11492
|
+
| Scenario | What |
|
|
11493
|
+
|----------|------|
|
|
11494
|
+
| Workflow flow | Flowchart (steps, branches, ask points) |
|
|
11495
|
+
| Step-level comparison | Comparison cards |
|
|
11496
|
+
| Data flow / {{refs}} | Flowchart |
|
|
11256
11497
|
|
|
11257
11498
|
## Phase 0: Load Skills
|
|
11258
11499
|
|
|
@@ -11262,20 +11503,122 @@ that achieve it. Acceptance = workflow outcome meets the usable state.
|
|
|
11262
11503
|
|
|
11263
11504
|
## Phase 1: Design
|
|
11264
11505
|
|
|
11265
|
-
1.
|
|
11266
|
-
|
|
11267
|
-
|
|
11268
|
-
4.
|
|
11506
|
+
1. **Establish the goal model FIRST** \u2014 real goal / user expectation /
|
|
11507
|
+
consumer / usable state ([[agent-architecture|Goal Model]]); record
|
|
11508
|
+
it in the parent task. It drives the expected output spec (Phase
|
|
11509
|
+
1.5) and verification (Phase 4). Then analyze the process: map
|
|
11510
|
+
every step, branch, data dependency.
|
|
11511
|
+
2. **Choose implementation mode per step \u2014 ASK the user** (present as
|
|
11512
|
+
comparison cards). Each step's logic is either inline or \`ref\`:
|
|
11513
|
+
- **inline prompt** \u2014 logic lives in the step's prompt. Fast, no
|
|
11514
|
+
extra agents. Cost: not reusable, no own tools, verified ONLY via
|
|
11515
|
+
the integration eval. OK for trivial one-off glue steps.
|
|
11516
|
+
- **ref sub-agent** \u2014 the step delegates to a registered agent with
|
|
11517
|
+
its own tools/model/skills (built via [[agent-build]], prompt =
|
|
11518
|
+
"Load [[skill-name]] and follow it"). Reusable, independently
|
|
11519
|
+
verified (Phase 2.6). Use when the step needs tools, non-trivial
|
|
11520
|
+
or reusable logic, or independent verification.
|
|
11521
|
+
Present the per-step choice with trade-offs and let the user
|
|
11522
|
+
decide \u2014 NEVER silently pick inline or ref. When in doubt, ask.
|
|
11523
|
+
3. **Identify knowledge per step** \u2014 for each step, determine the domain
|
|
11524
|
+
knowledge it needs:
|
|
11525
|
+
- Existing skill covers it \u2192 reference [[skill-name]] in the step
|
|
11526
|
+
- No skill yet, but the knowledge is reusable or non-trivial \u2192
|
|
11527
|
+
plan to create it (Phase 1.5)
|
|
11528
|
+
- Trivial one-off logic \u2192 may stay inline in the prompt (accept the
|
|
11529
|
+
trade-off: it is not reusable or individually verifiable)
|
|
11530
|
+
4. Design using the YAML linear DSL (steps, parallel, map, if, ask).
|
|
11531
|
+
5. **Present the design as a Flowchart widget** (\`show_widget\`) \u2014 every
|
|
11532
|
+
step, branch, and \`ask\` interaction point. Walk through it with the
|
|
11533
|
+
user step-by-step (each step's responsibility, branch logic, ask
|
|
11534
|
+
points). CONFIRM via \`ask_user_to_clarify\` \u2014 never build without
|
|
11535
|
+
explicit user approval.
|
|
11536
|
+
|
|
11537
|
+
## Phase 1.5: Expected Output Specification (mandatory \u2014 goal-driven)
|
|
11538
|
+
|
|
11539
|
+
Define the workflow's EXPECTED OUTPUT SPEC from the goal model BEFORE
|
|
11540
|
+
writing skills or building: what the final outcome looks like, per
|
|
11541
|
+
consumer (0.1.5). This is the acceptance standard \u2014 [[eval-verify]]
|
|
11542
|
+
contentAssertion derives from it. HARD RULE: if the target/expected
|
|
11543
|
+
output is unclear, ask the user \u2014 never guess.
|
|
11544
|
+
Present the spec, confirm with the user, record in the parent task.
|
|
11545
|
+
|
|
11546
|
+
## Phase 2: Create Skills (for missing knowledge)
|
|
11547
|
+
|
|
11548
|
+
For each planned skill (Phase 1.2): write SKILL.md (frontmatter +
|
|
11549
|
+
body encoding the domain rules). Present each for user approval.
|
|
11550
|
+
When 3+ skills share a domain \u2192 create a MOC ([[domain-moc]]).
|
|
11551
|
+
If a ref step needs an agent \u2192 build it via [[agent-build]] (agent
|
|
11552
|
+
prompt = "Load [[skill-name]] and follow it" \u2014 thin, knowledge in
|
|
11553
|
+
skill). Order: sub-agents/skills first, then the workflow that
|
|
11554
|
+
references them.
|
|
11555
|
+
|
|
11556
|
+
## Phase 2.6: Verify components FIRST (mandatory)
|
|
11557
|
+
|
|
11558
|
+
Every agent referenced by a \`ref\` step is a component with its OWN
|
|
11559
|
+
independent eval (eval-{ref-agent-id}) \u2014 run it and pass it BEFORE
|
|
11560
|
+
building the integration eval. The workflow cannot be considered tested
|
|
11561
|
+
until: \u2460 each ref'd agent's eval passes independently, \u2461 then the
|
|
11562
|
+
workflow's integration eval (branch paths + ask handling) passes. See
|
|
11563
|
+
[[eval-verify|Layered verification]].
|
|
11564
|
+
|
|
11565
|
+
## Phase 3: Build
|
|
11566
|
+
|
|
11567
|
+
1. **Configure middleware & tools for the workflow itself** \u2014 inline
|
|
11568
|
+
steps run on the workflow's own model/tools: call
|
|
11569
|
+
\`list_middleware_types\` first; add what the workflow needs \u2014 skill
|
|
11570
|
+
(if steps load [[skill-name]]), widget, ask_user_to_clarify, etc.
|
|
11571
|
+
Tool filtering via \`allowedTools\`. \`ref\` steps use the ref'd
|
|
11572
|
+
agent's own tools/model \u2014 nothing to configure here. Choose
|
|
11573
|
+
\`modelKey\` only when a specific model is required (default
|
|
11574
|
+
otherwise).
|
|
11575
|
+
2. Call \`create_workflow\` with \`skillLoaded: true\` \u2014 steps reference
|
|
11576
|
+
[[skill-name]] or \`ref\` to skill-loading agents.
|
|
11577
|
+
3. Then \`validate_workflow(id)\`.
|
|
11578
|
+
|
|
11579
|
+
## Phase 4: Test (mandatory \u2014 no eval, no trust tier)
|
|
11580
|
+
|
|
11581
|
+
The authoritative verification is [[eval-verify]] \u2014 cases derive from
|
|
11582
|
+
the expected output spec (Phase 1.5). A workflow without a passing eval
|
|
11583
|
+
stays at "configured" forever \u2014 trust can never upgrade
|
|
11584
|
+
([[completion-gate]], no skip option).
|
|
11585
|
+
|
|
11586
|
+
**Testing is managed through the eval project (eval-{workflow-id})
|
|
11587
|
+
and its cases \u2014 the same governance as agents.** Temporary or quick
|
|
11588
|
+
checks (ad-hoc runs, previewing behavior) may use [[review-agent]] as
|
|
11589
|
+
an interactive pre-check \u2014 but that is NOT the workflow's test suite:
|
|
11590
|
+
it never upgrades trust and never replaces the eval project. Only the
|
|
11591
|
+
eval project's cases passing determine "tested".
|
|
11592
|
+
|
|
11593
|
+
**Test order \u2014 components first, then integration:**
|
|
11594
|
+
1. Each \`ref\`'d agent: its OWN eval (eval-{ref-agent-id}) must pass
|
|
11595
|
+
independently (Phase 2.6) \u2014 fix it in isolation, not through the
|
|
11596
|
+
workflow.
|
|
11597
|
+
2. Then the workflow's integration eval (eval-{workflow-id}): one case
|
|
11598
|
+
per branch path (if/map/parallel); \`ask\` steps via case
|
|
11599
|
+
interruptPolicy (auto-approve/canned-response to test the flow AFTER
|
|
11600
|
+
the pause, stop to test up to the pause); assertions are exact \u2014
|
|
11601
|
+
the pipeline is deterministic.
|
|
11602
|
+
|
|
11603
|
+
Workflow trust upgrade requires BOTH layers passing.
|
|
11604
|
+
[[review-agent]] is an optional cheap pre-check only.
|
|
11605
|
+
|
|
11606
|
+
## Editing workflows
|
|
11607
|
+
|
|
11608
|
+
Get the current YAML \u2192 present the diff \u2192 confirm with the user \u2192
|
|
11609
|
+
\`update_workflow(id, ...)\`. Never re-create.
|
|
11610
|
+
After ANY change: verified resets to unverified and the eval is re-run
|
|
11611
|
+
([[eval-verify]]) \u2014 the change is not done until the eval passes again.
|
|
11612
|
+
Deleting: warn if any step \`ref\`s it \u2192 confirm \u2192 \`delete_agent\`.
|
|
11269
11613
|
|
|
11270
|
-
##
|
|
11271
|
-
|
|
11272
|
-
Call \`create_workflow\` with \`skillLoaded: true\`, then
|
|
11273
|
-
\`validate_workflow(id)\`.
|
|
11274
|
-
|
|
11275
|
-
## Phase 3: Test
|
|
11614
|
+
## Metadata
|
|
11276
11615
|
|
|
11277
|
-
|
|
11278
|
-
|
|
11616
|
+
Always set metadata on workflow creation. At minimum:
|
|
11617
|
+
- verified: "unverified" (upgraded after eval passes)
|
|
11618
|
+
- version: "1.0" (bump on each update)
|
|
11619
|
+
- source: the material name or "user-description"
|
|
11620
|
+
When trust upgrades, update BOTH the skill's verified frontmatter and
|
|
11621
|
+
the workflow's metadata.verified \u2014 they must stay in sync.
|
|
11279
11622
|
|
|
11280
11623
|
## No edges, state fields, or end step
|
|
11281
11624
|
The engine auto-generates them. Steps execute top-to-bottom in written
|
|
@@ -11501,10 +11844,20 @@ async function resolveConnections(type, connections, tenantId2) {
|
|
|
11501
11844
|
throw err;
|
|
11502
11845
|
}
|
|
11503
11846
|
}
|
|
11504
|
-
async function createCommonMiddlewares(middlewareConfigs, filesystemBackend, fsIsExised, tenantId2) {
|
|
11847
|
+
async function createCommonMiddlewares(middlewareConfigs, filesystemBackend, fsIsExised, tenantId2, model) {
|
|
11505
11848
|
const middlewares = [];
|
|
11506
11849
|
middlewares.push(createUnknownToolHandlerMiddleware());
|
|
11507
11850
|
middlewares.push(createModelSelectorMiddleware());
|
|
11851
|
+
middlewares.push(createPatchToolCallsMiddleware());
|
|
11852
|
+
if (model) {
|
|
11853
|
+
middlewares.push(
|
|
11854
|
+
summarizationMiddleware({
|
|
11855
|
+
model,
|
|
11856
|
+
trigger: { tokens: 17e4 },
|
|
11857
|
+
keep: { messages: 6 }
|
|
11858
|
+
})
|
|
11859
|
+
);
|
|
11860
|
+
}
|
|
11508
11861
|
const filesystemConfig = middlewareConfigs.find((m) => m.type === "filesystem");
|
|
11509
11862
|
const clawConfig = middlewareConfigs.find((m) => m.type === "claw");
|
|
11510
11863
|
const needsFilesystemBackend = filesystemConfig?.enabled || clawConfig?.enabled;
|
|
@@ -11836,7 +12189,7 @@ var ReActAgentGraphBuilder = class {
|
|
|
11836
12189
|
const stateSchema2 = createReactAgentSchema(params.stateSchema);
|
|
11837
12190
|
const middlewareConfigs = params.middleware || [];
|
|
11838
12191
|
const filesystemBackend = createFilesystemBackendFactory(middlewareConfigs);
|
|
11839
|
-
const middlewares = await createCommonMiddlewares(middlewareConfigs, filesystemBackend, void 0, params.tenantId);
|
|
12192
|
+
const middlewares = await createCommonMiddlewares(middlewareConfigs, filesystemBackend, void 0, params.tenantId, params.model);
|
|
11840
12193
|
return createAgent({
|
|
11841
12194
|
model: params.model,
|
|
11842
12195
|
tools,
|
|
@@ -11854,17 +12207,16 @@ var ReActAgentGraphBuilder = class {
|
|
|
11854
12207
|
import {
|
|
11855
12208
|
createAgent as createAgent3,
|
|
11856
12209
|
humanInTheLoopMiddleware as humanInTheLoopMiddleware2,
|
|
11857
|
-
anthropicPromptCachingMiddleware
|
|
11858
|
-
summarizationMiddleware
|
|
12210
|
+
anthropicPromptCachingMiddleware
|
|
11859
12211
|
} from "langchain";
|
|
11860
12212
|
|
|
11861
12213
|
// src/deep_agent_new/middleware/subagents.ts
|
|
11862
12214
|
import { z as z42 } from "zod/v3";
|
|
11863
12215
|
import {
|
|
11864
|
-
createMiddleware as
|
|
12216
|
+
createMiddleware as createMiddleware11,
|
|
11865
12217
|
createAgent as createAgent2,
|
|
11866
12218
|
tool as tool40,
|
|
11867
|
-
ToolMessage as
|
|
12219
|
+
ToolMessage as ToolMessage4,
|
|
11868
12220
|
humanInTheLoopMiddleware
|
|
11869
12221
|
} from "langchain";
|
|
11870
12222
|
import { Command as Command3, getCurrentTaskInput as getCurrentTaskInput2, GraphInterrupt as GraphInterrupt3 } from "@langchain/langgraph";
|
|
@@ -13810,7 +14162,7 @@ var AgentInstanceManager = class _AgentInstanceManager {
|
|
|
13810
14162
|
var agentInstanceManager = AgentInstanceManager.getInstance();
|
|
13811
14163
|
|
|
13812
14164
|
// src/middlewares/taskMiddleware.ts
|
|
13813
|
-
import { createMiddleware as
|
|
14165
|
+
import { createMiddleware as createMiddleware10, tool as tool39 } from "langchain";
|
|
13814
14166
|
import { z as z41 } from "zod";
|
|
13815
14167
|
import { GraphInterrupt as GraphInterrupt2, interrupt as interrupt3 } from "@langchain/langgraph";
|
|
13816
14168
|
function getRunConfig(config) {
|
|
@@ -14118,26 +14470,37 @@ function createTaskMiddleware() {
|
|
|
14118
14470
|
});
|
|
14119
14471
|
}
|
|
14120
14472
|
};
|
|
14121
|
-
return
|
|
14473
|
+
return createMiddleware10({
|
|
14122
14474
|
name: "TaskMiddleware",
|
|
14123
14475
|
contextSchema,
|
|
14124
14476
|
wrapModelCall: async (request, handler) => {
|
|
14125
14477
|
const taskPrompt = `## Task Management
|
|
14126
14478
|
|
|
14127
|
-
You
|
|
14479
|
+
You have the \`manage_task\` tool to track work. Task management is the
|
|
14480
|
+
ongoing record of a GOAL and its ACCEPTANCE CRITERIA.
|
|
14128
14481
|
|
|
14129
|
-
### When to create a task
|
|
14482
|
+
### When to create a task (universal rule)
|
|
14483
|
+
- The goal is clear and you are about to start real work \u2192 create the
|
|
14484
|
+
parent task FIRST (with Objective + Acceptance Criteria in the
|
|
14485
|
+
description), then execute. This is a core duty, not optional.
|
|
14130
14486
|
- The user explicitly asks you to track, manage, or follow up on work
|
|
14131
14487
|
- The work spans multiple sessions or might need resumption later
|
|
14132
14488
|
- The user needs to review or approve output before it is considered done
|
|
14133
14489
|
- There are multiple independent work items the user wants visibility into
|
|
14134
14490
|
|
|
14135
14491
|
### When NOT to create a task
|
|
14492
|
+
- Goal not yet clear (still clarifying) \u2014 clarify first, then create
|
|
14136
14493
|
- One-shot lookups or simple Q&A ("what is X?", "search for Y")
|
|
14137
14494
|
- Internal exploration steps you take to understand the problem (use \`write_todos\` for your execution plan instead)
|
|
14138
14495
|
- Trivial single-step actions that complete in the same turn
|
|
14139
14496
|
- Conversational or informational requests with no deliverable
|
|
14140
14497
|
|
|
14498
|
+
### Keep the task current
|
|
14499
|
+
A task is the living record of the goal + its acceptance criteria.
|
|
14500
|
+
Update the description as work proceeds: check off criteria as met,
|
|
14501
|
+
revise criteria when scope changes, append progress. Status changes
|
|
14502
|
+
only when the criteria are truly met.
|
|
14503
|
+
|
|
14141
14504
|
### Ownership defaults
|
|
14142
14505
|
- No params: ownerType defaults to "user" with current user's ID
|
|
14143
14506
|
- ownerType="agent": auto-fills ownerId from current agent (subtask for yourself)
|
|
@@ -14191,6 +14554,29 @@ var taskPlugin = {
|
|
|
14191
14554
|
skills: {
|
|
14192
14555
|
"task-definition": `## Using manage_task
|
|
14193
14556
|
|
|
14557
|
+
### When to create a task (universal rule)
|
|
14558
|
+
|
|
14559
|
+
Create a task BEFORE executing whenever the goal is clear and you know
|
|
14560
|
+
what to do \u2014 not just for long or complex work:
|
|
14561
|
+
|
|
14562
|
+
- Goal is understood and you are about to start real work \u2192 create the
|
|
14563
|
+
parent task FIRST, then execute. The task tracks the work.
|
|
14564
|
+
- Goal is NOT yet clear (still clarifying, gathering requirements) \u2192
|
|
14565
|
+
do NOT create a task yet. Clarify first, create the task once scope
|
|
14566
|
+
is defined.
|
|
14567
|
+
- One-shot lookups, trivial single-step actions, or internal reasoning
|
|
14568
|
+
\u2192 no task needed.
|
|
14569
|
+
|
|
14570
|
+
Rule of thumb: if you can write an Objective and Acceptance Criteria
|
|
14571
|
+
for it, create the task before doing it. Work without a task = work
|
|
14572
|
+
without a contract.
|
|
14573
|
+
|
|
14574
|
+
**A task is the living record of the goal + its acceptance criteria.**
|
|
14575
|
+
Keep the description current as work proceeds: update the Objective
|
|
14576
|
+
when the target evolves, check off criteria as they are met, revise
|
|
14577
|
+
criteria when scope changes. Reading the task always tells you what
|
|
14578
|
+
"done" means; an outdated task is a broken contract.
|
|
14579
|
+
|
|
14194
14580
|
### Task description format
|
|
14195
14581
|
|
|
14196
14582
|
When creating a task with manage_task, write the description in this Markdown structure:
|
|
@@ -14392,7 +14778,7 @@ function returnCommandWithStateUpdate(result, toolCallId) {
|
|
|
14392
14778
|
update: {
|
|
14393
14779
|
...stateUpdate,
|
|
14394
14780
|
messages: [
|
|
14395
|
-
new
|
|
14781
|
+
new ToolMessage4({
|
|
14396
14782
|
content: lastMessage?.content || "Task Failed to complete",
|
|
14397
14783
|
tool_call_id: toolCallId,
|
|
14398
14784
|
name: "task"
|
|
@@ -14585,7 +14971,7 @@ You are executing a persistent task (ID: ${input.taskId}). Use manage_task.updat
|
|
|
14585
14971
|
return new Command3({
|
|
14586
14972
|
update: {
|
|
14587
14973
|
messages: [
|
|
14588
|
-
new
|
|
14974
|
+
new ToolMessage4({
|
|
14589
14975
|
content: `Async task started: ${subagent_thread_id}
|
|
14590
14976
|
${description}
|
|
14591
14977
|
The result will be delivered as a notification when complete. Do not poll.`,
|
|
@@ -14619,7 +15005,7 @@ The result will be delivered as a notification when complete. Do not poll.`,
|
|
|
14619
15005
|
return new Command3({
|
|
14620
15006
|
update: {
|
|
14621
15007
|
messages: [
|
|
14622
|
-
new
|
|
15008
|
+
new ToolMessage4({
|
|
14623
15009
|
content: error instanceof Error ? error.message : "Task Failed to complete",
|
|
14624
15010
|
tool_call_id: config.toolCall.id,
|
|
14625
15011
|
name: "task"
|
|
@@ -14856,7 +15242,7 @@ function createSubAgentMiddleware(options) {
|
|
|
14856
15242
|
);
|
|
14857
15243
|
}
|
|
14858
15244
|
const effectiveSystemPrompt = allowAsync ? systemPrompt + getAsyncPromptText() : systemPrompt;
|
|
14859
|
-
return
|
|
15245
|
+
return createMiddleware11({
|
|
14860
15246
|
name: "subAgentMiddleware",
|
|
14861
15247
|
tools: allTools,
|
|
14862
15248
|
wrapModelCall: async (request, handler) => {
|
|
@@ -14875,53 +15261,6 @@ ${effectiveSystemPrompt}` : effectiveSystemPrompt;
|
|
|
14875
15261
|
});
|
|
14876
15262
|
}
|
|
14877
15263
|
|
|
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
15264
|
// src/deep_agent_new/middleware/date.ts
|
|
14926
15265
|
import { createMiddleware as createMiddleware12, tool as tool41 } from "langchain";
|
|
14927
15266
|
import { z as z43 } from "zod";
|
|
@@ -17834,36 +18173,20 @@ ${BASE_PROMPT}` : BASE_PROMPT;
|
|
|
17834
18173
|
createFilesystemMiddleware({
|
|
17835
18174
|
backend: filesystemBackend
|
|
17836
18175
|
}),
|
|
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
18176
|
// Subagent middleware: Anthropic prompt caching for improved performance
|
|
17844
18177
|
anthropicPromptCachingMiddleware({
|
|
17845
18178
|
unsupportedModelBehavior: "ignore"
|
|
17846
18179
|
}),
|
|
17847
|
-
// Subagent middleware: Patches tool calls for compatibility
|
|
17848
|
-
createPatchToolCallsMiddleware(),
|
|
17849
18180
|
...customMiddleware
|
|
17850
18181
|
],
|
|
17851
18182
|
defaultInterruptOn: interruptOn,
|
|
17852
18183
|
subagents,
|
|
17853
18184
|
generalPurposeAgent: true
|
|
17854
18185
|
}),
|
|
17855
|
-
// Automatically summarizes conversation history when token limits are approached
|
|
17856
|
-
summarizationMiddleware({
|
|
17857
|
-
model,
|
|
17858
|
-
trigger: { tokens: 17e4 },
|
|
17859
|
-
keep: { messages: 6 }
|
|
17860
|
-
}),
|
|
17861
18186
|
// Enables Anthropic prompt caching for improved performance and reduced costs
|
|
17862
18187
|
anthropicPromptCachingMiddleware({
|
|
17863
18188
|
unsupportedModelBehavior: "ignore"
|
|
17864
|
-
})
|
|
17865
|
-
// Patches tool calls to ensure compatibility across different model providers
|
|
17866
|
-
createPatchToolCallsMiddleware()
|
|
18189
|
+
})
|
|
17867
18190
|
];
|
|
17868
18191
|
if (interruptOn) {
|
|
17869
18192
|
middleware.push(humanInTheLoopMiddleware2({ interruptOn }));
|
|
@@ -17918,7 +18241,7 @@ var DeepAgentGraphBuilder = class {
|
|
|
17918
18241
|
}));
|
|
17919
18242
|
const middlewareConfigs = params.middleware || [];
|
|
17920
18243
|
const filesystemBackend = createFilesystemBackendFactory(middlewareConfigs);
|
|
17921
|
-
const middlewares = await createCommonMiddlewares(middlewareConfigs, filesystemBackend, true, params.tenantId);
|
|
18244
|
+
const middlewares = await createCommonMiddlewares(middlewareConfigs, filesystemBackend, true, params.tenantId, params.model);
|
|
17922
18245
|
const deepAgent = createDeepAgent({
|
|
17923
18246
|
tools,
|
|
17924
18247
|
model: params.model,
|
|
@@ -19534,7 +19857,7 @@ var TeamAgentGraphBuilder = class {
|
|
|
19534
19857
|
});
|
|
19535
19858
|
const middlewareConfigs = params.middleware || [];
|
|
19536
19859
|
let filesystemBackend = createFilesystemBackendFactory(middlewareConfigs);
|
|
19537
|
-
const middlewares = await createCommonMiddlewares(middlewareConfigs);
|
|
19860
|
+
const middlewares = await createCommonMiddlewares(middlewareConfigs, void 0, void 0, void 0, params.model);
|
|
19538
19861
|
if (!filesystemBackend) {
|
|
19539
19862
|
filesystemBackend = async (config2) => {
|
|
19540
19863
|
return new StateBackend(config2);
|
|
@@ -19951,7 +20274,7 @@ var WorkflowAgentGraphBuilder = class {
|
|
|
19951
20274
|
const checkpointer = getCheckpointSaver("default");
|
|
19952
20275
|
const tools = params.tools.map((t) => t.executor).filter(Boolean);
|
|
19953
20276
|
const middlewareConfigs = params.middleware || [];
|
|
19954
|
-
const middlewares = await createCommonMiddlewares(middlewareConfigs, void 0, false, params.tenantId);
|
|
20277
|
+
const middlewares = await createCommonMiddlewares(middlewareConfigs, void 0, false, params.tenantId, params.model);
|
|
19955
20278
|
const askMiddlewares = await createCommonMiddlewares([
|
|
19956
20279
|
{
|
|
19957
20280
|
id: "ask_user_to_clarify",
|
|
@@ -19961,7 +20284,7 @@ var WorkflowAgentGraphBuilder = class {
|
|
|
19961
20284
|
enabled: true,
|
|
19962
20285
|
config: {}
|
|
19963
20286
|
}
|
|
19964
|
-
], void 0, false);
|
|
20287
|
+
], void 0, false, void 0, params.model);
|
|
19965
20288
|
const noWrapMiddlewares = stripWrapModelCallHook(middlewares);
|
|
19966
20289
|
const noWrapAskMiddlewares = stripWrapModelCallHook(askMiddlewares);
|
|
19967
20290
|
console.log(`[WF BUILDER] building default agent | toolCount=${tools.length} | middlewareCount=${middlewares.length}`);
|
|
@@ -21638,6 +21961,40 @@ Call the \`skill\` tool with skill_name: "agent-architecture" to load the
|
|
|
21638
21961
|
authoritative workflow. Never announce that you will follow a skill \u2014
|
|
21639
21962
|
load it and follow its content. If the load fails, retry once, then report it.
|
|
21640
21963
|
|
|
21964
|
+
TASK MANAGEMENT IS A CORE DUTY, not a per-skill option. Whenever the
|
|
21965
|
+
goal is clear and you know what to do, create a task FIRST (manage_task)
|
|
21966
|
+
before executing \u2014 for any multi-step work: learning, building,
|
|
21967
|
+
modifying, fixing, anything with an Objective and Acceptance Criteria.
|
|
21968
|
+
- **Check for duplicates BEFORE creating** \u2014 always manage_task
|
|
21969
|
+
action: "list" first (filter ownerType: "agent"). If a task with the
|
|
21970
|
+
same objective already exists (e.g. from an interrupted session),
|
|
21971
|
+
RESUME it instead of creating a new one.
|
|
21972
|
+
- **Decompose into subtasks** \u2014 after the parent task, create a
|
|
21973
|
+
subtask per work item / phase (e.g. design, build, eval), each with
|
|
21974
|
+
its own Objective + Acceptance Criteria.
|
|
21975
|
+
- **Update on completion** \u2014 every finished subtask and the parent:
|
|
21976
|
+
manage_task update(status: "completed", result: "what was done").
|
|
21977
|
+
Use interrupted/failed with summary/failureReason when blocked or
|
|
21978
|
+
unable. Status must always reflect reality \u2014 never leave a finished
|
|
21979
|
+
task dangling in an in-progress state.
|
|
21980
|
+
See [[task-tracking]].
|
|
21981
|
+
The sub-skills below only ADD their own task details on top of this
|
|
21982
|
+
universal duty.
|
|
21983
|
+
|
|
21984
|
+
BUILD GATES \u2014 hard behavioral requirements, no exceptions, no skipping:
|
|
21985
|
+
- Creating a WORKFLOW ([[design-workflow]]): \u2460 show the design as a
|
|
21986
|
+
Flowchart widget (every step, branch, ask point) \u2461 walk through it
|
|
21987
|
+
step-by-step with the user \u2462 ask inline-vs-ref per step \u2463 CONFIRM via
|
|
21988
|
+
ask_user_to_clarify \u2014 only then call create_workflow.
|
|
21989
|
+
- Creating an AGENT ([[agent-build]]): \u2460 present the design with
|
|
21990
|
+
show_widget \u2461 confirm via ask_user_to_clarify \u2014 only then call
|
|
21991
|
+
create_agent.
|
|
21992
|
+
- Both: if the goal model (real goal / consumer / usable state) is
|
|
21993
|
+
unclear, ask BEFORE designing \u2014 never guess.
|
|
21994
|
+
The skills document WHY and HOW; these gates are the unskippable
|
|
21995
|
+
minimum. If you cannot satisfy a gate (e.g. user says skip), record it
|
|
21996
|
+
and proceed only on the user's explicit instruction.
|
|
21997
|
+
|
|
21641
21998
|
Your sub-skills (accessible via the MOC or direct loading):
|
|
21642
21999
|
- [[learn-capability]] \u2014 Learn from any source material \u2192 skills + agents
|
|
21643
22000
|
- [[agent-build]] \u2014 Design and build single agents (REACT/DEEP_AGENT)
|
|
@@ -21802,7 +22159,15 @@ var agentArchitectConfig = {
|
|
|
21802
22159
|
id: "task",
|
|
21803
22160
|
type: "task",
|
|
21804
22161
|
name: "Task",
|
|
21805
|
-
description: "
|
|
22162
|
+
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.",
|
|
22163
|
+
enabled: true,
|
|
22164
|
+
config: {}
|
|
22165
|
+
},
|
|
22166
|
+
{
|
|
22167
|
+
id: "code_eval",
|
|
22168
|
+
type: "code_eval",
|
|
22169
|
+
name: "Code Evaluation",
|
|
22170
|
+
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
22171
|
enabled: true,
|
|
21807
22172
|
config: {}
|
|
21808
22173
|
},
|
|
@@ -25424,6 +25789,15 @@ function parseJudgeVerdict(raw) {
|
|
|
25424
25789
|
return { error: error instanceof Error ? error.message : String(error) };
|
|
25425
25790
|
}
|
|
25426
25791
|
}
|
|
25792
|
+
var MAX_INTERRUPT_RESUMES = 5;
|
|
25793
|
+
function resolveInterruptResponse(policy, interrupt5) {
|
|
25794
|
+
if (policy.mode === "auto-approve") return policy.value ?? "\u540C\u610F";
|
|
25795
|
+
if (policy.mode === "auto-reject") return policy.value ?? "\u62D2\u7EDD";
|
|
25796
|
+
return policy.value ?? "";
|
|
25797
|
+
}
|
|
25798
|
+
function interruptValueText(value) {
|
|
25799
|
+
return typeof value === "string" ? value : JSON.stringify(value ?? "");
|
|
25800
|
+
}
|
|
25427
25801
|
var _LatticeEval = class _LatticeEval {
|
|
25428
25802
|
constructor(config = {}) {
|
|
25429
25803
|
this.inMemoryLogs = [];
|
|
@@ -25490,7 +25864,8 @@ var _LatticeEval = class _LatticeEval {
|
|
|
25490
25864
|
return acc;
|
|
25491
25865
|
}, {});
|
|
25492
25866
|
}
|
|
25493
|
-
async executeAgentStep(step, threadId, inputMessage, files) {
|
|
25867
|
+
async executeAgentStep(step, threadId, inputMessage, files, interruptPolicy) {
|
|
25868
|
+
const hitlEvents = [];
|
|
25494
25869
|
this.log("Executing agent step", {
|
|
25495
25870
|
agent_id: step.agent_id,
|
|
25496
25871
|
thread_id: threadId,
|
|
@@ -25508,19 +25883,74 @@ var _LatticeEval = class _LatticeEval {
|
|
|
25508
25883
|
};
|
|
25509
25884
|
const agent = agentInstanceManager.getAgent(agentParams);
|
|
25510
25885
|
try {
|
|
25511
|
-
const
|
|
25512
|
-
|
|
25513
|
-
|
|
25514
|
-
|
|
25886
|
+
const stepInput = {
|
|
25887
|
+
message: step.override_message || inputMessage,
|
|
25888
|
+
files: this.buildFileEntries(files)
|
|
25889
|
+
};
|
|
25890
|
+
let result = await agent.invokeWithState({ input: stepInput });
|
|
25891
|
+
let resumeCount = 0;
|
|
25892
|
+
let pendingInterrupt;
|
|
25893
|
+
let interrupts = Array.isArray(result?.__interrupt__) ? result.__interrupt__ : [];
|
|
25894
|
+
while (interrupts.length > 0) {
|
|
25895
|
+
const interrupt5 = interrupts[0];
|
|
25896
|
+
if (!interrupt5) break;
|
|
25897
|
+
const policy = interruptPolicy;
|
|
25898
|
+
if (!policy || policy.mode === "stop" || resumeCount >= MAX_INTERRUPT_RESUMES) {
|
|
25899
|
+
pendingInterrupt = interrupt5;
|
|
25900
|
+
break;
|
|
25515
25901
|
}
|
|
25516
|
-
|
|
25902
|
+
const response = resolveInterruptResponse(policy, interrupt5);
|
|
25903
|
+
hitlEvents.push({
|
|
25904
|
+
type: "interrupt",
|
|
25905
|
+
id: interrupt5.id,
|
|
25906
|
+
value: interrupt5.value
|
|
25907
|
+
});
|
|
25908
|
+
this.log("Auto-resolving HITL interrupt", {
|
|
25909
|
+
agent_id: step.agent_id,
|
|
25910
|
+
thread_id: threadId,
|
|
25911
|
+
mode: policy.mode,
|
|
25912
|
+
interrupt_id: interrupt5.id,
|
|
25913
|
+
response,
|
|
25914
|
+
resume_count: resumeCount + 1
|
|
25915
|
+
});
|
|
25916
|
+
result = await agent.invokeWithState({ input: stepInput, command: { resume: response } });
|
|
25917
|
+
hitlEvents.push({
|
|
25918
|
+
type: "interrupt_response",
|
|
25919
|
+
id: interrupt5.id,
|
|
25920
|
+
mode: policy.mode,
|
|
25921
|
+
response
|
|
25922
|
+
});
|
|
25923
|
+
resumeCount++;
|
|
25924
|
+
interrupts = Array.isArray(result?.__interrupt__) ? result.__interrupt__ : [];
|
|
25925
|
+
}
|
|
25926
|
+
if (pendingInterrupt) {
|
|
25927
|
+
hitlEvents.push({
|
|
25928
|
+
type: "interrupt",
|
|
25929
|
+
id: pendingInterrupt.id,
|
|
25930
|
+
value: pendingInterrupt.value
|
|
25931
|
+
});
|
|
25932
|
+
this.log("Agent step interrupted by HITL (human input requested)", {
|
|
25933
|
+
agent_id: step.agent_id,
|
|
25934
|
+
thread_id: threadId,
|
|
25935
|
+
interrupt_id: pendingInterrupt.id,
|
|
25936
|
+
auto_resolved: resumeCount
|
|
25937
|
+
});
|
|
25938
|
+
} else {
|
|
25939
|
+
this.log("Agent step completed", {
|
|
25940
|
+
agent_id: step.agent_id,
|
|
25941
|
+
thread_id: threadId,
|
|
25942
|
+
response_keys: result ? Object.keys(result) : [],
|
|
25943
|
+
auto_resolved: resumeCount
|
|
25944
|
+
});
|
|
25945
|
+
}
|
|
25517
25946
|
const responseData = { success: true, ...result };
|
|
25518
|
-
|
|
25519
|
-
|
|
25520
|
-
|
|
25521
|
-
|
|
25522
|
-
|
|
25523
|
-
|
|
25947
|
+
return {
|
|
25948
|
+
threadId,
|
|
25949
|
+
responseData,
|
|
25950
|
+
interrupted: pendingInterrupt ? true : void 0,
|
|
25951
|
+
interrupt: pendingInterrupt,
|
|
25952
|
+
hitlEvents
|
|
25953
|
+
};
|
|
25524
25954
|
} catch (error) {
|
|
25525
25955
|
const message = error instanceof Error ? error.message : String(error);
|
|
25526
25956
|
this.log("Agent step failed", {
|
|
@@ -25583,15 +26013,32 @@ var _LatticeEval = class _LatticeEval {
|
|
|
25583
26013
|
});
|
|
25584
26014
|
let currentThreadId = threadId;
|
|
25585
26015
|
let lastResponseData = null;
|
|
26016
|
+
let interrupt5;
|
|
25586
26017
|
for (const step of evalCase.steps) {
|
|
25587
26018
|
const result = await this.executeAgentStep(
|
|
25588
26019
|
step,
|
|
25589
26020
|
currentThreadId,
|
|
25590
26021
|
evalCase.input.message,
|
|
25591
|
-
evalCase.input.files || {}
|
|
26022
|
+
evalCase.input.files || {},
|
|
26023
|
+
evalCase.interruptPolicy
|
|
25592
26024
|
);
|
|
25593
26025
|
currentThreadId = result.threadId;
|
|
25594
26026
|
lastResponseData = result.responseData;
|
|
26027
|
+
for (const evt of result.hitlEvents) {
|
|
26028
|
+
if (evt.type === "interrupt") {
|
|
26029
|
+
this.lastMessages.push({
|
|
26030
|
+
role: "interrupt",
|
|
26031
|
+
content: `HITL \u6682\u505C\uFF1AAgent \u8BF7\u6C42\u4EBA\u5DE5\u8F93\u5165 \u2014 ${interruptValueText(evt.value)}`,
|
|
26032
|
+
id: evt.id
|
|
26033
|
+
});
|
|
26034
|
+
} else {
|
|
26035
|
+
this.lastMessages.push({
|
|
26036
|
+
role: "interrupt_response",
|
|
26037
|
+
content: `\u5DF2\u81EA\u52A8\u54CD\u5E94\uFF08\u6D4B\u8BD5\u7B56\u7565 ${evt.mode}\uFF09\uFF1A${evt.response}`,
|
|
26038
|
+
id: evt.id
|
|
26039
|
+
});
|
|
26040
|
+
}
|
|
26041
|
+
}
|
|
25595
26042
|
const existingIds = new Set(this.lastMessages.map((m) => m.id).filter(Boolean));
|
|
25596
26043
|
if (result.responseData?.messages && Array.isArray(result.responseData.messages)) {
|
|
25597
26044
|
for (const msg of result.responseData.messages) {
|
|
@@ -25613,6 +26060,13 @@ var _LatticeEval = class _LatticeEval {
|
|
|
25613
26060
|
} else {
|
|
25614
26061
|
content = String(msg.content || "");
|
|
25615
26062
|
}
|
|
26063
|
+
if (Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {
|
|
26064
|
+
const toolCallStr = msg.tool_calls.map(
|
|
26065
|
+
(tc) => `tool_call: ${tc.name}(${JSON.stringify(tc.args ?? {})})`
|
|
26066
|
+
).join("\n");
|
|
26067
|
+
content = content ? `${content}
|
|
26068
|
+
${toolCallStr}` : toolCallStr;
|
|
26069
|
+
}
|
|
25616
26070
|
this.lastMessages.push({
|
|
25617
26071
|
role,
|
|
25618
26072
|
content,
|
|
@@ -25624,13 +26078,21 @@ var _LatticeEval = class _LatticeEval {
|
|
|
25624
26078
|
}
|
|
25625
26079
|
}
|
|
25626
26080
|
}
|
|
26081
|
+
if (result.interrupted) {
|
|
26082
|
+
interrupt5 = result.interrupt;
|
|
26083
|
+
this.log("Case paused for HITL \u2014 remaining steps skipped; judge will evaluate the pause", {
|
|
26084
|
+
case_id: evalCase.caseId,
|
|
26085
|
+
interrupt_id: interrupt5?.id
|
|
26086
|
+
});
|
|
26087
|
+
break;
|
|
26088
|
+
}
|
|
25627
26089
|
}
|
|
25628
26090
|
this.log("All agent steps completed", {
|
|
25629
26091
|
case_id: evalCase.caseId,
|
|
25630
26092
|
final_thread_id: currentThreadId,
|
|
25631
26093
|
message_count: this.lastMessages.length
|
|
25632
26094
|
});
|
|
25633
|
-
const finalOutput = this.extractFinalMessage(lastResponseData);
|
|
26095
|
+
const finalOutput = interrupt5 ? typeof interrupt5.value === "string" ? interrupt5.value : JSON.stringify(interrupt5.value ?? "") : this.extractFinalMessage(lastResponseData);
|
|
25634
26096
|
this.lastFinalOutput = finalOutput;
|
|
25635
26097
|
const trajectory = this.buildTrajectory();
|
|
25636
26098
|
this.log("Final output extracted", {
|
|
@@ -25689,6 +26151,8 @@ ${rubricsSection}
|
|
|
25689
26151
|
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
26152
|
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
26153
|
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
|
|
26154
|
+
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
|
|
26155
|
+
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
26156
|
|
|
25693
26157
|
# \u8F93\u51FA\u683C\u5F0F\uFF08\u4EC5JSON\uFF09
|
|
25694
26158
|
\u4F60\u5FC5\u987B\u4EC5\u4EE5 JSON \u683C\u5F0F\u56DE\u590D\uFF0C\u7ED3\u6784\u5982\u4E0B\uFF1A
|
|
@@ -25843,7 +26307,9 @@ ${rubricsSection}
|
|
|
25843
26307
|
pass,
|
|
25844
26308
|
final_score: finalScore,
|
|
25845
26309
|
dimension_results: dimensionResults,
|
|
25846
|
-
summary: parsedResult.summary || testResultContent
|
|
26310
|
+
summary: parsedResult.summary || testResultContent,
|
|
26311
|
+
interrupted: interrupt5 ? true : void 0,
|
|
26312
|
+
interrupt: interrupt5 ? { id: interrupt5.id, value: interrupt5.value } : void 0
|
|
25847
26313
|
};
|
|
25848
26314
|
}
|
|
25849
26315
|
};
|
|
@@ -25858,6 +26324,8 @@ async function evaluateLatticeCaseWithLogs(evalCase, config) {
|
|
|
25858
26324
|
return {
|
|
25859
26325
|
caseId: evalCase.caseId,
|
|
25860
26326
|
result,
|
|
26327
|
+
interrupted: result?.interrupted,
|
|
26328
|
+
interrupt: result?.interrupt,
|
|
25861
26329
|
duration_ms: meta.duration_ms,
|
|
25862
26330
|
thread_id: meta.thread_id,
|
|
25863
26331
|
judge_thread_id: meta.judge_thread_id,
|
|
@@ -25940,7 +26408,8 @@ function resolveTemplateCase(templateCase, templates) {
|
|
|
25940
26408
|
eval: {
|
|
25941
26409
|
content_assertion: templateCase.eval.content_assertion,
|
|
25942
26410
|
eval_rubrics: templateCase.eval.eval_rubrics || template.default_case.eval?.eval_rubrics
|
|
25943
|
-
}
|
|
26411
|
+
},
|
|
26412
|
+
interruptPolicy: templateCase.interruptPolicy ?? template.default_case.interruptPolicy
|
|
25944
26413
|
};
|
|
25945
26414
|
return resolvedCase;
|
|
25946
26415
|
}
|
|
@@ -26006,6 +26475,8 @@ var LatticeEvalSuite = class {
|
|
|
26006
26475
|
result: run.result,
|
|
26007
26476
|
error: run.error,
|
|
26008
26477
|
error_stack: run.error_stack,
|
|
26478
|
+
interrupted: run.interrupted,
|
|
26479
|
+
interrupt: run.interrupt,
|
|
26009
26480
|
duration_ms: run.duration_ms,
|
|
26010
26481
|
thread_id: run.thread_id,
|
|
26011
26482
|
judge_thread_id: run.judge_thread_id,
|
|
@@ -26038,6 +26509,8 @@ var LatticeEvalSuite = class {
|
|
|
26038
26509
|
result: run.result,
|
|
26039
26510
|
error: run.error,
|
|
26040
26511
|
error_stack: run.error_stack,
|
|
26512
|
+
interrupted: run.interrupted,
|
|
26513
|
+
interrupt: run.interrupt,
|
|
26041
26514
|
duration_ms: run.duration_ms,
|
|
26042
26515
|
thread_id: run.thread_id,
|
|
26043
26516
|
judge_thread_id: run.judge_thread_id,
|
|
@@ -26247,24 +26720,29 @@ Running batch: ${this.project.projectName} (${this.getSuiteNames().length} suite
|
|
|
26247
26720
|
let total_cases = 0;
|
|
26248
26721
|
let passed_cases = 0;
|
|
26249
26722
|
let failed_cases = 0;
|
|
26723
|
+
let interrupted_cases = 0;
|
|
26250
26724
|
const suites = [];
|
|
26251
26725
|
for (const [suiteName, caseResults] of results.entries()) {
|
|
26252
26726
|
const suiteTotal = caseResults.length;
|
|
26253
26727
|
const suitePassed = caseResults.filter((r) => r.result?.pass).length;
|
|
26728
|
+
const suiteInterrupted = caseResults.filter((r) => r.interrupted).length;
|
|
26254
26729
|
const suiteFailed = suiteTotal - suitePassed;
|
|
26255
26730
|
total_cases += suiteTotal;
|
|
26256
26731
|
passed_cases += suitePassed;
|
|
26257
26732
|
failed_cases += suiteFailed;
|
|
26733
|
+
interrupted_cases += suiteInterrupted;
|
|
26258
26734
|
suites.push({
|
|
26259
26735
|
suiteName,
|
|
26260
26736
|
total_cases: suiteTotal,
|
|
26261
26737
|
passed_cases: suitePassed,
|
|
26262
26738
|
failed_cases: suiteFailed,
|
|
26739
|
+
interrupted_cases: suiteInterrupted,
|
|
26263
26740
|
cases: caseResults.map((r) => ({
|
|
26264
26741
|
caseId: r.caseId,
|
|
26265
26742
|
pass: r.result?.pass,
|
|
26266
26743
|
final_score: r.result?.final_score,
|
|
26267
|
-
error: r.error
|
|
26744
|
+
error: r.error,
|
|
26745
|
+
interrupted: r.interrupted
|
|
26268
26746
|
}))
|
|
26269
26747
|
});
|
|
26270
26748
|
}
|
|
@@ -26282,13 +26760,14 @@ Running batch: ${this.project.projectName} (${this.getSuiteNames().length} suite
|
|
|
26282
26760
|
total_cases,
|
|
26283
26761
|
passed_cases,
|
|
26284
26762
|
failed_cases,
|
|
26763
|
+
interrupted_cases,
|
|
26285
26764
|
pass_rate: total_cases > 0 ? passed_cases / total_cases : 0
|
|
26286
26765
|
},
|
|
26287
26766
|
suites
|
|
26288
26767
|
};
|
|
26289
26768
|
console.log(`
|
|
26290
26769
|
=== 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)}%`);
|
|
26770
|
+
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
26771
|
return { batch_id, results, report };
|
|
26293
26772
|
}
|
|
26294
26773
|
};
|
|
@@ -28237,10 +28716,21 @@ Write assertions as objective, verifiable natural language:
|
|
|
28237
28716
|
- steps: [{agent_id: "a"}, {agent_id: "b", override_message: "Based on..."}] for chain
|
|
28238
28717
|
- outputType: "message_content" or "file_content"
|
|
28239
28718
|
|
|
28719
|
+
## Designing HITL Cases
|
|
28720
|
+
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:
|
|
28721
|
+
|
|
28722
|
+
- 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.
|
|
28723
|
+
- interruptPolicy: {mode: "auto-reject"} \u2014 inject "\u62D2\u7EDD"; tests the rejection path.
|
|
28724
|
+
- interruptPolicy: {mode: "canned-response", value: "..."} \u2014 inject an exact human reply; tests behavior under a specific response.
|
|
28725
|
+
- 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).
|
|
28726
|
+
|
|
28727
|
+
Choose per the assertion: if the assertion describes what happens AFTER the human input, you MUST set an auto-resolve policy.
|
|
28728
|
+
|
|
28240
28729
|
## Checklist
|
|
28241
28730
|
1. Check existing assets with read_eval to avoid duplication
|
|
28242
28731
|
2. Start with 3-5 high-signal cases
|
|
28243
|
-
3.
|
|
28732
|
+
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
|
|
28733
|
+
4. Confirm with user before calling manage_eval
|
|
28244
28734
|
`,
|
|
28245
28735
|
"eval-run-and-govern": `---
|
|
28246
28736
|
name: eval-run-and-govern
|
|
@@ -28250,8 +28740,11 @@ description: Run agent evaluations, interpret results, diagnose failures, and re
|
|
|
28250
28740
|
# Agent Governance Loop
|
|
28251
28741
|
|
|
28252
28742
|
1. Discover project \u2192 read_eval list_projects
|
|
28253
|
-
2. Start evaluation \u2192 run_eval start(projectId) \u2014
|
|
28254
|
-
|
|
28743
|
+
2. Start evaluation \u2192 run_eval start(projectId) \u2014 SYNCHRONOUS by default:
|
|
28744
|
+
blocks up to ~150s and returns the FINAL RESULTS in one call.
|
|
28745
|
+
Hold-out (validation) runs return aggregates only.
|
|
28746
|
+
3. If still running (or use wait: false for fire-and-forget) \u2192 poll
|
|
28747
|
+
run_eval status(runId, sleepMs) \u2014 pass sleepMs to pace (15s, 30s, 60s, max 120s)
|
|
28255
28748
|
4. If runnerAlive=false and status=running \u2192 ORPHANED (gateway restart).
|
|
28256
28749
|
resume(runId) marks it failed automatically \u2014 then start a new run.
|
|
28257
28750
|
5. Get results \u2192 read_eval get_run_results(runId) for per-case dimension scores
|
|
@@ -28320,10 +28813,12 @@ function sanitize(obj) {
|
|
|
28320
28813
|
}
|
|
28321
28814
|
function aggregateHoldoutResults(results) {
|
|
28322
28815
|
const passed = results.filter((r) => r.pass).length;
|
|
28816
|
+
const interrupted = results.filter((r) => r.interrupted).length;
|
|
28323
28817
|
return {
|
|
28324
28818
|
holdout: true,
|
|
28325
28819
|
passedCases: passed,
|
|
28326
28820
|
failedCases: results.length - passed,
|
|
28821
|
+
interruptedCases: interrupted,
|
|
28327
28822
|
passRate: results.length > 0 ? passed / results.length : 0,
|
|
28328
28823
|
totalCases: results.length
|
|
28329
28824
|
};
|
|
@@ -28394,13 +28889,8 @@ function createReadEvalTool() {
|
|
|
28394
28889
|
if (!run) return JSON.stringify({ success: false, error: "Run not found" });
|
|
28395
28890
|
const results = await store.getResultsByRun(tid, input.runId);
|
|
28396
28891
|
if (run.holdout) {
|
|
28397
|
-
const passed = results.filter((r) => r.pass).length;
|
|
28398
28892
|
data = {
|
|
28399
|
-
|
|
28400
|
-
passedCases: passed,
|
|
28401
|
-
failedCases: results.length - passed,
|
|
28402
|
-
passRate: results.length > 0 ? passed / results.length : 0,
|
|
28403
|
-
totalCases: results.length,
|
|
28893
|
+
...aggregateHoldoutResults(results),
|
|
28404
28894
|
message: "Hold-out run \u2014 per-case results withheld. Only aggregates are available."
|
|
28405
28895
|
};
|
|
28406
28896
|
} else {
|
|
@@ -28435,6 +28925,7 @@ ACTIONS:
|
|
|
28435
28925
|
- get_run_results(runId) \u2014 per-case results with dimension scores.
|
|
28436
28926
|
For HOLD-OUT (validation-only) runs: returns AGGREGATES ONLY
|
|
28437
28927
|
(passRate, counts) \u2014 per-case details are withheld by design.
|
|
28928
|
+
Cases paused for human input (HITL) carry interrupted=true and are judged \u2014 the judge evaluates whether pausing was correct business behavior.
|
|
28438
28929
|
- get_project_report(projectId) \u2014 aggregated stats across all runs`,
|
|
28439
28930
|
schema: schema6
|
|
28440
28931
|
}
|
|
@@ -28465,7 +28956,11 @@ function createManageEvalTool() {
|
|
|
28465
28956
|
steps: z66.array(z66.object({ agent_id: z66.string(), override_message: z66.string().optional() })).optional(),
|
|
28466
28957
|
outputType: z66.enum(["file_content", "message_content"]).optional(),
|
|
28467
28958
|
contentAssertion: z66.string().optional(),
|
|
28468
|
-
rubrics: z66.array(z66.object({ name: z66.string(), weight: z66.number(), description: z66.string() })).optional()
|
|
28959
|
+
rubrics: z66.array(z66.object({ name: z66.string(), weight: z66.number(), description: z66.string() })).optional(),
|
|
28960
|
+
interruptPolicy: z66.object({
|
|
28961
|
+
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"),
|
|
28962
|
+
value: z66.string().optional().describe("Response to inject (defaults: \u540C\u610F / \u62D2\u7EDD; required for canned-response)")
|
|
28963
|
+
}).optional().describe("Optional for create_case/update_case \u2014 how HITL interrupts are handled")
|
|
28469
28964
|
});
|
|
28470
28965
|
return tool62(
|
|
28471
28966
|
async (input, exeConfig) => {
|
|
@@ -28523,7 +29018,8 @@ function createManageEvalTool() {
|
|
|
28523
29018
|
steps: input.steps,
|
|
28524
29019
|
outputType: input.outputType,
|
|
28525
29020
|
contentAssertion: input.contentAssertion,
|
|
28526
|
-
rubrics: input.rubrics
|
|
29021
|
+
rubrics: input.rubrics,
|
|
29022
|
+
interruptPolicy: input.interruptPolicy
|
|
28527
29023
|
});
|
|
28528
29024
|
break;
|
|
28529
29025
|
case "update_case":
|
|
@@ -28531,7 +29027,8 @@ function createManageEvalTool() {
|
|
|
28531
29027
|
inputMessage: input.inputMessage,
|
|
28532
29028
|
contentAssertion: input.contentAssertion,
|
|
28533
29029
|
steps: input.steps,
|
|
28534
|
-
rubrics: input.rubrics
|
|
29030
|
+
rubrics: input.rubrics,
|
|
29031
|
+
interruptPolicy: input.interruptPolicy
|
|
28535
29032
|
});
|
|
28536
29033
|
break;
|
|
28537
29034
|
case "delete_case":
|
|
@@ -28556,9 +29053,13 @@ Project: create_project(name, description?, judgeModelKey?, concurrency?) | upda
|
|
|
28556
29053
|
**When creating a project from within a workspace, the workspace/project context is
|
|
28557
29054
|
automatically bound \u2014 eval runs will execute in the same workspace.**
|
|
28558
29055
|
Suite: create_suite(projectId, name) | update_suite | delete_suite
|
|
28559
|
-
Case: create_case(suiteId, inputMessage, steps, outputType, contentAssertion, inputFiles?, rubrics?)
|
|
29056
|
+
Case: create_case(suiteId, inputMessage, steps, outputType, contentAssertion, inputFiles?, rubrics?, interruptPolicy?)
|
|
28560
29057
|
steps is [{agent_id, override_message?}]. outputType is "file_content" or "message_content".
|
|
28561
|
-
rubrics is [{name, weight, description}]. | update_case | delete_case
|
|
29058
|
+
rubrics is [{name, weight, description}]. | update_case | delete_case
|
|
29059
|
+
interruptPolicy: {mode: "stop"|"auto-approve"|"auto-reject"|"canned-response", value?} \u2014 how HITL interrupts are handled:
|
|
29060
|
+
stop (default): case pauses at the human-input request; the judge evaluates the pause as business behavior.
|
|
29061
|
+
auto-approve / auto-reject: the runner injects approval/rejection and tests the FULL flow after the pause.
|
|
29062
|
+
canned-response: injects the exact value (simulates a specific human reply).`,
|
|
28562
29063
|
schema: schema6
|
|
28563
29064
|
}
|
|
28564
29065
|
);
|
|
@@ -28672,6 +29173,8 @@ ACTIONS:
|
|
|
28672
29173
|
- start(projectId, suiteIds?, caseIds?, wait?) \u2014 begin evaluation (optionally only the listed suites, and/or only the listed cases).
|
|
28673
29174
|
wait=true (DEFAULT): SYNCHRONOUS \u2014 blocks up to ~150s and returns the FINAL RESULTS in one call:
|
|
28674
29175
|
{ status, results } with per-case pass/score (hold-out/validation runs: aggregates only \u2014 per-case details withheld by design).
|
|
29176
|
+
Cases paused for human input (HITL) carry interrupted=true and ARE judged \u2014 the judge evaluates whether requesting
|
|
29177
|
+
the human was the correct behavior (assertions like "must approve first" PASS; "must be autonomous" FAIL). interruptedCases counts these.
|
|
28675
29178
|
If the run exceeds 150s: returns { runId, status: "running" } \u2014 NOT an error \u2014 then poll with status/resume until completed.
|
|
28676
29179
|
wait=false: fire-and-forget \u2014 returns { runId } immediately; poll with status.
|
|
28677
29180
|
- status(runId, sleepMs?) \u2014 sleep sleepMs first (to pace polling), then return current status + runnerAlive flag:
|
|
@@ -28977,67 +29480,64 @@ verification choice, then start benchmarking.
|
|
|
28977
29480
|
|
|
28978
29481
|
## Task Tracking \u2014 see [[task-tracking]]
|
|
28979
29482
|
|
|
28980
|
-
**
|
|
28981
|
-
|
|
28982
|
-
|
|
28983
|
-
|
|
28984
|
-
|
|
28985
|
-
|
|
28986
|
-
|
|
28987
|
-
never mark a subtask completed while eval
|
|
28988
|
-
runs with manage_task list.
|
|
29483
|
+
**Universal principle**: once the goal is clear and you know what to
|
|
29484
|
+
do, create the parent task BEFORE executing (manage_task create, see
|
|
29485
|
+
[[task-tracking]]). In this workflow: after Phase 0 clarification
|
|
29486
|
+
completes and the user confirmed the path (end of 0.5), create the
|
|
29487
|
+
parent task; then a subtask per phase as you start it. The parent task
|
|
29488
|
+
description carries the GOAL MODEL (0.1.5) as Objective + Acceptance
|
|
29489
|
+
Criteria; the expected output spec (2.6) updates the criteria. Update
|
|
29490
|
+
status to reflect reality \u2014 never mark a subtask completed while eval
|
|
29491
|
+
fails. Resume interrupted runs with manage_task list.
|
|
28989
29492
|
|
|
28990
29493
|
Widgets: call \`load_guidelines\` ONCE before your first \`show_widget\`
|
|
28991
29494
|
(show_widget hard-requires it), then reuse.
|
|
28992
29495
|
|
|
28993
29496
|
---
|
|
28994
29497
|
|
|
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.
|
|
29498
|
+
## Phase 1: Explore (goal-driven path finding)
|
|
29499
|
+
|
|
29500
|
+
The goal model (0.1.5) is set. Now EXPLORE how to achieve it \u2014 actively
|
|
29501
|
+
hunt for the path, do not passively read. Three exploration fronts:
|
|
29502
|
+
|
|
29503
|
+
**A. Existing assets (reuse, don't rebuild):**
|
|
29504
|
+
- \`list_agents\` / \`load_skills\` \u2192 are there existing agents or skills
|
|
29505
|
+
that already do part of this? Reuse them (update_agent if needed)
|
|
29506
|
+
instead of building from scratch. This is a goal-relevant check, not
|
|
29507
|
+
a materials step.
|
|
29508
|
+
- \`list_tools\` / \`list_middleware_types\` \u2192 what capabilities exist
|
|
29509
|
+
that the goal needs (parsing, data access, browser...)?
|
|
29510
|
+
- \`list_connections\` \u2192 are the data sources the goal depends on
|
|
29511
|
+
already connected?
|
|
29512
|
+
- If verification will happen (0.2 \u2460 or \u2461): concurrently discover
|
|
29513
|
+
executor candidates (see \xA75). \u2460 \u2192 data-access tools; \u2461 \u2192 independence.
|
|
29514
|
+
|
|
29515
|
+
**B. Material probing (by material type):**
|
|
29516
|
+
- **User-description**: the requirements come from the conversation.
|
|
29517
|
+
Extract goal, inputs, outputs, constraints \u2014 then explore the
|
|
29518
|
+
implementation path (A + feasibility): what assets exist, what tools
|
|
29519
|
+
are needed, what blockers stand between the goal and its achievement.
|
|
29520
|
+
- **Document** (PDF / spec / manual): benchmark engines as needed \u2014
|
|
29521
|
+
parse directly with the chosen engine (0.3 \u2460-\u2464) or run
|
|
29522
|
+
document-parser-benchmark. Engine selection IS distilled knowledge:
|
|
29523
|
+
it builds the agent (engine's parse_document into middleware), seeds
|
|
29524
|
+
the skill (feature signature + winning engine), and designs the tests
|
|
29525
|
+
(engine output as case baseline input).
|
|
29526
|
+
- **API spec**: read directly \u2014 endpoints, schemas, examples.
|
|
29527
|
+
- **Conversation**: extract workflow, decisions, corrections.
|
|
29528
|
+
- **Spreadsheet**: parse cells directly.
|
|
29529
|
+
|
|
29530
|
+
**C. Feasibility (path blockers):**
|
|
29531
|
+
- What stands between the goal and achievement? Missing tools, missing
|
|
29532
|
+
connections, data access, permission constraints, ambiguous
|
|
29533
|
+
requirements.
|
|
29534
|
+
- Does the goal require orchestration (\u2192 Phase 2 split decision)?
|
|
29535
|
+
- Surface these in the recommendation (Phase 1.5) \u2014 the user decides
|
|
29536
|
+
the path, informed by what exploration found.
|
|
29537
|
+
|
|
29538
|
+
Exploration is COMPLETE when you can answer: what exists to reuse,
|
|
29539
|
+
what must be built, what tools/connections are needed, and what blocks
|
|
29540
|
+
the goal. Do not go to design without this map.
|
|
29041
29541
|
|
|
29042
29542
|
---
|
|
29043
29543
|
|
|
@@ -29052,17 +29552,21 @@ candidate and assess (Validation Agent Design \xA70) \u2014 state which are
|
|
|
29052
29552
|
usable and which are not, with reasons. For \u2460, the executor needs data
|
|
29053
29553
|
tools + independence. For \u2461, independence only. If no candidate fits,
|
|
29054
29554
|
plan to build one via \xA75.
|
|
29055
|
-
Present
|
|
29555
|
+
Present the EXPLORATION map as widget \u2014 what exists to reuse, what
|
|
29556
|
+
must be built, tools/connections needed, blockers found \u2014 then
|
|
29557
|
+
recommend the IMPLEMENTATION PATH: reuse existing X, build new Y,
|
|
29558
|
+
split or single agent (Phase 2 input). MUST call
|
|
29056
29559
|
\`ask_user_to_clarify\` NOW:
|
|
29057
29560
|
{
|
|
29058
29561
|
"questions": [{
|
|
29059
|
-
"question": "Confirm the
|
|
29562
|
+
"question": "Confirm the recommended path?",
|
|
29060
29563
|
"options": ["Confirm", "Adjust"],
|
|
29061
29564
|
"type": "single",
|
|
29062
29565
|
"required": true
|
|
29063
29566
|
}]
|
|
29064
29567
|
}
|
|
29065
|
-
Skills planning belongs to Phase 2 \u2014 this phase presents
|
|
29568
|
+
Skills planning belongs to Phase 2 \u2014 this phase presents the path, not
|
|
29569
|
+
the detailed plan.
|
|
29066
29570
|
|
|
29067
29571
|
---
|
|
29068
29572
|
|
|
@@ -29130,9 +29634,53 @@ user-description material this IS the core phase; for material-based
|
|
|
29130
29634
|
learning it designs the agent that runs the learned skill. Agent
|
|
29131
29635
|
metadata (verified/version/source) must be set on creation.
|
|
29132
29636
|
|
|
29637
|
+
## Phase 2.6: Expected Output Specification (mandatory \u2014 goal-driven)
|
|
29638
|
+
|
|
29639
|
+
**Expectations come FIRST, before writing the skill.** You cannot write
|
|
29640
|
+
a skill (or test cases) without a target. Define the expected output
|
|
29641
|
+
specification from the goal model (0.1.5: real goal / consumer / usable
|
|
29642
|
+
state) BEFORE Phase 3:
|
|
29643
|
+
|
|
29644
|
+
**HARD RULE \u2014 never guess the target.** If the goal, the expected
|
|
29645
|
+
output, the consumer, or the usable state is unclear at ANY point
|
|
29646
|
+
before writing test cases, you MUST ask the user via
|
|
29647
|
+
\`ask_user_to_clarify\` \u2014 do NOT proceed with an assumed expectation.
|
|
29648
|
+
A test case written against a guessed expectation is worthless: it
|
|
29649
|
+
validates the wrong thing. When in doubt, ask.
|
|
29650
|
+
|
|
29651
|
+
Per skill, define the EXPECTED OUTPUT SPEC (based on intent 0.1 and
|
|
29652
|
+
consumer 0.1.5):
|
|
29653
|
+
- Extract data \u2192 expected fields (names, types, formats), required vs
|
|
29654
|
+
optional, output structure (JSON schema shape, table columns)
|
|
29655
|
+
- Validate rules \u2192 expected judgment outcomes (pass/fail conditions),
|
|
29656
|
+
boundary values, and the reason format
|
|
29657
|
+
- Execute workflow \u2192 expected step sequence, decision points, final
|
|
29658
|
+
outcome shape
|
|
29659
|
+
- Answer knowledge \u2192 expected answer form (with/without sources,
|
|
29660
|
+
length, structure)
|
|
29661
|
+
|
|
29662
|
+
This spec IS the acceptance standard. Phase 4 contentAssertion must be
|
|
29663
|
+
derived from it (not invented at case-writing time). Present the
|
|
29664
|
+
expected output spec to the user and MUST call \`ask_user_to_clarify\`
|
|
29665
|
+
NOW per skill:
|
|
29666
|
+
{
|
|
29667
|
+
"questions": [{
|
|
29668
|
+
"question": "Confirm the expected output spec for {skill-name}?",
|
|
29669
|
+
"options": ["Confirm", "Adjust"],
|
|
29670
|
+
"type": "single",
|
|
29671
|
+
"required": true,
|
|
29672
|
+
"allowOther": true
|
|
29673
|
+
}]
|
|
29674
|
+
}
|
|
29675
|
+
Record the confirmed spec in the parent task description. This replaces
|
|
29676
|
+
guess-then-confirm: the skill is written TO MEET the spec, and test
|
|
29677
|
+
cases assert AGAINST the spec \u2014 no expectation is invented later.
|
|
29678
|
+
|
|
29133
29679
|
## Phase 3: Create Skills
|
|
29134
29680
|
|
|
29135
|
-
Write SKILL.md to \`/root/.agents/skills/{name}/SKILL.md\` one at a time
|
|
29681
|
+
Write SKILL.md to \`/root/.agents/skills/{name}/SKILL.md\` one at a time,
|
|
29682
|
+
designed TO MEET the expected output spec confirmed in Phase 2.6 \u2014 the
|
|
29683
|
+
skill encodes how to produce the spec's expected output.
|
|
29136
29684
|
Show the skill content in text first, then MUST call
|
|
29137
29685
|
\`ask_user_to_clarify\` NOW per skill:
|
|
29138
29686
|
{
|
|
@@ -29426,7 +29974,8 @@ This learning loop adds its own scenario rules:
|
|
|
29426
29974
|
- Business usability (output reaches the goal's "usable state")
|
|
29427
29975
|
- Consumer fit (format/contract satisfies who uses the result)
|
|
29428
29976
|
contentAssertion must encode the usable state from the goal model
|
|
29429
|
-
(0.1.5),
|
|
29977
|
+
(0.1.5), derived from the EXPECTED OUTPUT SPEC (Phase 2.6) \u2014 never
|
|
29978
|
+
invented at case-writing time.
|
|
29430
29979
|
|
|
29431
29980
|
1. One suite per skill per source: cases test "can this skill do it" \u2014
|
|
29432
29981
|
never mix skills in one suite
|
|
@@ -29469,6 +30018,12 @@ Learning-specific suite guidance:
|
|
|
29469
30018
|
- User-description material: {skill}-requirement-derived \u2014 cases from
|
|
29470
30019
|
user's described requirements
|
|
29471
30020
|
|
|
30021
|
+
**Case expectations come from the confirmed spec** (Phase 2.6): the
|
|
30022
|
+
contentAssertion of every case must be derived from the expected output
|
|
30023
|
+
spec, NOT invented at case-writing time. If a case needs an expectation
|
|
30024
|
+
not in the spec, go back and extend the spec with user confirmation
|
|
30025
|
+
first \u2014 never guess expectations on the fly.
|
|
30026
|
+
|
|
29472
30027
|
[[completion-gate]] applies \u2014 eval must pass before declaring done.
|
|
29473
30028
|
|
|
29474
30029
|
## Phase 5: Retrospective
|