qlogicagent 2.15.10 → 2.16.1

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.
Files changed (56) hide show
  1. package/dist/agent.js +24 -20
  2. package/dist/cli.js +572 -515
  3. package/dist/index.js +571 -514
  4. package/dist/orchestration.js +9 -9
  5. package/dist/protocol.js +1 -1
  6. package/dist/types/agent/tool-loop/artifact-final-contract.d.ts +21 -0
  7. package/dist/types/agent/tool-loop/tool-failure-policy.d.ts +1 -0
  8. package/dist/types/agent/tool-loop.d.ts +2 -0
  9. package/dist/types/agent/types.d.ts +7 -202
  10. package/dist/types/cli/acp-extended-handlers.d.ts +1 -0
  11. package/dist/types/cli/core-tools/agent-tool-service.d.ts +1 -0
  12. package/dist/types/cli/handlers/agents-handler.d.ts +8 -0
  13. package/dist/types/cli/handlers/product-handler.d.ts +21 -2
  14. package/dist/types/cli/handlers/workflow-handler.d.ts +5 -0
  15. package/dist/types/cli/tool-bootstrap-core-registration.d.ts +5 -0
  16. package/dist/types/cli/turn-core.d.ts +2 -0
  17. package/dist/types/contracts/index.d.ts +1 -0
  18. package/dist/types/contracts/turn-event.d.ts +235 -0
  19. package/dist/types/orchestration/agent-instance.d.ts +45 -2
  20. package/dist/types/orchestration/agent-roster.d.ts +17 -0
  21. package/dist/types/orchestration/dag-scheduler.d.ts +27 -0
  22. package/dist/types/orchestration/product-budget.d.ts +7 -1
  23. package/dist/types/orchestration/product-persistence.d.ts +31 -0
  24. package/dist/types/orchestration/product-planner.d.ts +123 -0
  25. package/dist/types/orchestration/product-run-coordinator.d.ts +17 -1
  26. package/dist/types/orchestration/product-worktree.d.ts +3 -0
  27. package/dist/types/orchestration/skill-improvement.d.ts +2 -19
  28. package/dist/types/orchestration/solo-evaluator.d.ts +10 -0
  29. package/dist/types/orchestration/solo-spec-builder.d.ts +4 -0
  30. package/dist/types/orchestration/workflow/n8n-import.d.ts +26 -32
  31. package/dist/types/orchestration/workflow/n8n-template-compat.d.ts +5 -0
  32. package/dist/types/orchestration/workflow/node-registry.d.ts +13 -0
  33. package/dist/types/orchestration/workflow/node-schema.d.ts +10 -0
  34. package/dist/types/orchestration/workflow/qla-executor-host.d.ts +7 -1
  35. package/dist/types/protocol/methods.d.ts +8 -1
  36. package/dist/types/protocol/notifications.d.ts +1 -1
  37. package/dist/types/protocol/wire/acp-agent-management.d.ts +38 -0
  38. package/dist/types/protocol/wire/acp-protocol.d.ts +1 -0
  39. package/dist/types/protocol/wire/agent-events.d.ts +3 -3
  40. package/dist/types/protocol/wire/agent-methods.d.ts +11 -1
  41. package/dist/types/protocol/wire/index.d.ts +1 -1
  42. package/dist/types/protocol/wire/notification-payloads.d.ts +39 -0
  43. package/dist/types/runtime/infra/acp-detector.d.ts +3 -0
  44. package/dist/types/runtime/infra/acp-protocol-adapter.d.ts +9 -0
  45. package/dist/types/runtime/ports/agent-execution-contracts.d.ts +2 -199
  46. package/dist/types/runtime/ports/tool-contracts.d.ts +6 -0
  47. package/dist/types/runtime/prompt/environment-context.d.ts +20 -1
  48. package/dist/types/skills/tools/ask-user-tool.d.ts +4 -2
  49. package/dist/types/skills/tools/shell/command-classification.d.ts +1 -0
  50. package/dist/types/skills/tools/tool-search-tool.d.ts +13 -0
  51. package/dist/types/skills/tools/tool-selection-eval.d.ts +49 -0
  52. package/dist/types/skills/tools/tool-selection-eval.dataset.d.ts +5 -0
  53. package/dist/types/skills/tools/write-tool.d.ts +2 -0
  54. package/dist/types/skills/tools.d.ts +21 -0
  55. package/dist/types/transport/acp-server.d.ts +1 -0
  56. package/package.json +2 -1
@@ -31,6 +31,9 @@ export interface Node {
31
31
  error?: string;
32
32
  startedAt?: number;
33
33
  completedAt?: number;
34
+ inputTokens?: number;
35
+ outputTokens?: number;
36
+ changedFiles?: string[];
34
37
  runIndex: number;
35
38
  maxIterations?: number;
36
39
  iteration?: number;
@@ -83,6 +86,9 @@ export declare class DagScheduler {
83
86
  markCompleted(id: string, out: {
84
87
  output?: unknown;
85
88
  firedPorts?: string[];
89
+ inputTokens?: number;
90
+ outputTokens?: number;
91
+ changedFiles?: string[];
86
92
  }): void;
87
93
  markFailed(id: string, error: string): void;
88
94
  markPaused(id: string): void;
@@ -108,6 +114,15 @@ export declare class DagScheduler {
108
114
  * Reset a failed node to pending. Optionally patches params (e.g. revised prompt).
109
115
  */
110
116
  retryNode(id: string, paramsPatch?: Record<string, unknown>): void;
117
+ /**
118
+ * Reset a completed/failed node AND all its transitive descendants back to pending for replay
119
+ * (CrewAI Crew.replay(task_id) parity), clearing their outputs. Ancestors are left untouched so
120
+ * their completed outputs continue feeding downstream task-context (getUpstreamOutputs) — replay
121
+ * re-runs the subtree while reusing upstream results. Pure state mutation: no scheduling.
122
+ *
123
+ * Returns the ids that were reset (the node + every descendant).
124
+ */
125
+ resetForReplay(id: string): string[];
111
126
  /** Merge patch into node.params. Node must be pending. */
112
127
  updateNodeParams(id: string, patch: Record<string, unknown>): void;
113
128
  /** Add an explicit edge. Validates no cycle. Validates ports exist on source. */
@@ -120,6 +135,15 @@ export declare class DagScheduler {
120
135
  * Missing fields use defaults.
121
136
  */
122
137
  restore(data: SerializedNode[]): void;
138
+ /**
139
+ * Returns the completed output of each direct dependency of this node.
140
+ * Used by Product orchestration to inject upstream task results into downstream prompts
141
+ * (CrewAI Task.context parity).
142
+ */
143
+ getUpstreamOutputs(id: string): {
144
+ taskId: string;
145
+ output: string;
146
+ }[];
123
147
  /** §3.1 edge predicate: source completed AND this port fired. */
124
148
  private edgeSatisfied;
125
149
  /** An edge is "dead" if the source is skipped, OR source completed but did NOT fire this port. */
@@ -161,6 +185,9 @@ export interface SerializedNode {
161
185
  error?: string;
162
186
  startedAt?: number;
163
187
  completedAt?: number;
188
+ inputTokens?: number;
189
+ outputTokens?: number;
190
+ changedFiles?: string[];
164
191
  runIndex: number;
165
192
  maxIterations?: number;
166
193
  iteration?: number;
@@ -20,6 +20,8 @@ export declare class ProductBudgetTracker {
20
20
  private maxTotalTokens?;
21
21
  private maxDuration?;
22
22
  private usedTokens;
23
+ private inputTokens;
24
+ private outputTokens;
23
25
  private startedAt;
24
26
  private warningEmitted;
25
27
  constructor(budget?: {
@@ -41,16 +43,20 @@ export declare class ProductBudgetTracker {
41
43
  * - "exceeded": over 100%, should pause
42
44
  */
43
45
  check(): BudgetCheck;
44
- /** Restore from persisted budget data. */
46
+ /** Restore from persisted budget data. (input/output optional for back-compat with older snapshots.) */
45
47
  restore(data: {
46
48
  usedTokens: number;
47
49
  startedAt: number;
48
50
  warningEmitted: boolean;
51
+ inputTokens?: number;
52
+ outputTokens?: number;
49
53
  }): void;
50
54
  /** Serialize for persistence. */
51
55
  serialize(): {
52
56
  usedTokens: number;
53
57
  startedAt: number;
54
58
  warningEmitted: boolean;
59
+ inputTokens: number;
60
+ outputTokens: number;
55
61
  };
56
62
  }
@@ -7,6 +7,7 @@
7
7
  import type { PathService } from "../runtime/ports/index.js";
8
8
  import type { ProductPhase, ProductInstanceDef } from "../protocol/wire/acp-agent-management.js";
9
9
  import type { SerializedNode } from "./dag-scheduler.js";
10
+ import type { PlanningSession } from "./product-planner.js";
10
11
  export interface PersistedProductState {
11
12
  productId: string;
12
13
  name: string;
@@ -23,6 +24,12 @@ export interface PersistedProductState {
23
24
  };
24
25
  createdAt: string;
25
26
  lastCheckpointAt: string;
27
+ /**
28
+ * Snapshot of the leader's multi-turn planning dialogue, so the leader regains its planning
29
+ * context after a resume (today this is in-process only and lost on restart). JSON-safe:
30
+ * PlanningSession is strings / arrays / plain objects (no functions, dates, or class instances).
31
+ */
32
+ leaderDialogue?: PlanningSession;
26
33
  }
27
34
  export interface ProductPersistenceOptions {
28
35
  pathService?: PathService;
@@ -33,3 +40,27 @@ export declare function saveProductState(state: PersistedProductState, cwd?: str
33
40
  export declare function loadProductState(productId: string, cwd?: string, options?: ProductPersistenceOptions): Promise<PersistedProductState | undefined>;
34
41
  /** List all product IDs with their persisted state. */
35
42
  export declare function listProducts(cwd?: string, options?: ProductPersistenceOptions): Promise<PersistedProductState[]>;
43
+ /**
44
+ * Save a full state snapshot into the checkpoints history directory.
45
+ * Uses `state.lastCheckpointAt` as the logical id (must be set before calling).
46
+ * Prunes old snapshots to keep at most MAX_CHECKPOINT_SNAPSHOTS entries.
47
+ */
48
+ export declare function saveProductCheckpointSnapshot(state: PersistedProductState, cwd?: string, options?: ProductPersistenceOptions): Promise<void>;
49
+ /**
50
+ * Load a specific checkpoint snapshot by its original ISO timestamp.
51
+ * Returns undefined if the snapshot does not exist.
52
+ */
53
+ export declare function loadProductCheckpointSnapshot(productId: string, timestamp: string, cwd?: string, options?: ProductPersistenceOptions): Promise<PersistedProductState | undefined>;
54
+ /**
55
+ * List all checkpoint timestamps for a product, sorted ascending (oldest first).
56
+ * Reads each snapshot file to recover the original ISO timestamp from state.lastCheckpointAt.
57
+ * Returns an empty array if the checkpoints directory does not exist.
58
+ */
59
+ export declare function listProductCheckpointTimestamps(productId: string, cwd?: string, options?: ProductPersistenceOptions): Promise<string[]>;
60
+ /**
61
+ * Restore a specific checkpoint as the latest product state.
62
+ * Loads the snapshot for `timestamp`, overwrites product-state.json with it,
63
+ * and returns the restored state. Returns undefined if the snapshot is not found
64
+ * (caller should fall back to the existing latest state).
65
+ */
66
+ export declare function restoreProductCheckpoint(productId: string, timestamp: string, cwd?: string, options?: ProductPersistenceOptions): Promise<PersistedProductState | undefined>;
@@ -47,9 +47,28 @@ export interface PlanningSession {
47
47
  maxTotalTokens?: number;
48
48
  maxDuration?: number;
49
49
  };
50
+ /**
51
+ * User-supplied allow-list of agent ids the leader may assign tasks to (planning AND execution-phase
52
+ * reassignment). Persisted AS-IS so the execution phase reuses the SAME constraint and a failure-driven
53
+ * reassign cannot pull in a non-participating agent. PRESENCE-based (must survive uncollapsed end to
54
+ * end): undefined → all ready agents; `[]` → ONLY the leader 小智 (user deselected every worker);
55
+ * `[ids]` → those + leader. See buildAgentRoster for the always-include-leader rule.
56
+ */
57
+ allowedAgents?: string[];
50
58
  createdAt: string;
51
59
  /** Last checkpoint timestamp for durable execution. */
52
60
  lastCheckpoint?: string;
61
+ /** A leader turn is currently running (planning is async/fire-and-forget) — block concurrent turns. */
62
+ turnInFlight?: boolean;
63
+ }
64
+ export interface ProductPlanAskQuestion {
65
+ question: string;
66
+ header: string;
67
+ options?: Array<{
68
+ label: string;
69
+ description?: string;
70
+ }>;
71
+ multiSelect?: boolean;
53
72
  }
54
73
  export interface PlannerCallbacks {
55
74
  log?: {
@@ -64,8 +83,17 @@ export interface PlannerCallbacks {
64
83
  onPlanningDelta?: (productId: string, text: string) => void;
65
84
  /** Leader sent a message to user (multi-turn). */
66
85
  onLeaderMessage?: (productId: string, message: string) => void;
86
+ /** Leader asked a structured clarifying question (turn-boundary); client renders an ask panel. */
87
+ onLeaderAsk?: (productId: string, askId: string, questions: ProductPlanAskQuestion[]) => void;
67
88
  /** Leader dynamically mutated the DAG during execution. */
68
89
  onDagMutated?: (productId: string, mutation: DagMutation) => void;
90
+ /** Live DAG progress for the execution-phase leader (filled by the orchestrator). */
91
+ getProgress?: (productId: string) => {
92
+ total: number;
93
+ completed: number;
94
+ running: number;
95
+ failed: number;
96
+ };
69
97
  }
70
98
  /** Describes a DAG mutation performed by the leader. */
71
99
  export interface DagMutation {
@@ -88,6 +116,27 @@ export declare class ProductPlanner {
88
116
  productId: string;
89
117
  plan: ProductPlan;
90
118
  }>;
119
+ /**
120
+ * Run one leader planning turn DETACHED from the RPC. Tokens stream live via product.planningDelta
121
+ * (the member turn.delta relay in product-coordinator); on completion this fires onPlanReady (parsed
122
+ * a structured plan), onLeaderAsk (a clarifying question), or onLeaderMessage (a non-plan reply).
123
+ * Never rejects into the caller — planning is fire-and-forget. Concurrent turns on the same session
124
+ * are blocked (a second prompt would cancel the in-flight one — the source of earlier "cancelled"
125
+ * turns) — EXCEPT the internal single-shot reprompt (isReprompt=true), which is allowed to run while
126
+ * turnInFlight is held by its parent turn and is itself guarded against further recursion.
127
+ */
128
+ private runLeaderTurn;
129
+ /**
130
+ * Route one leader response: plan → onPlanReady, ask → onLeaderAsk, else free-text → onLeaderMessage.
131
+ *
132
+ * Crucially, when the response LOOKS LIKE a plan (has a ```json fence or a "tasks" key) but fails to
133
+ * parse as one — the embedded-fence / unescaped-quote failure modes — we do NOT dump the raw JSON into
134
+ * the chat bubble. We re-prompt the leader EXACTLY ONCE with a strict "valid JSON only" instruction
135
+ * (guarded by `isReprompt` so it can't loop), and if that ALSO fails we emit a clean, user-facing
136
+ * fallback message instead of the raw JSON. A response only reaches onLeaderMessage verbatim when it
137
+ * does NOT look like a plan (genuine clarification / free-text).
138
+ */
139
+ private routeLeaderResponse;
91
140
  /**
92
141
  * Send a user message to the leader (works in planning and execution phases).
93
142
  * Returns the leader's response and optionally a finalized plan.
@@ -114,6 +163,21 @@ export declare class ProductPlanner {
114
163
  cancel(productId: string): Promise<void>;
115
164
  /** List active sessions. */
116
165
  listSessions(): PlanningSession[];
166
+ /**
167
+ * Ask the leader to judge whether a worker task's output satisfies its acceptanceCriteria.
168
+ * Returns { pass: true } immediately when there is no leader session (fail-open).
169
+ * If the response cannot be parsed at all, defaults to { pass: true } (lenient, like solo.specJudge).
170
+ */
171
+ reviewTaskOutput(productId: string, review: {
172
+ taskId: string;
173
+ instruction: string;
174
+ acceptanceCriteria: string;
175
+ output: string;
176
+ changedFiles?: string[];
177
+ }): Promise<{
178
+ pass: boolean;
179
+ feedback?: string;
180
+ }>;
117
181
  /**
118
182
  * Ask leader to evaluate execution state and propose DAG mutations.
119
183
  * Called by ProductOrchestrator when tasks fail or progress stalls.
@@ -141,6 +205,65 @@ export declare class ProductPlanner {
141
205
  private handlePlanningMessage;
142
206
  private handleExecutionMessage;
143
207
  private sendToLeader;
208
+ /**
209
+ * Extract a JSON object from the leader's reply. The leader (an LLM) formats the block
210
+ * inconsistently: ```json on its own line, ```json with the object inline, no language tag, or no
211
+ * fence at all. A non-greedy fence regex (`/```(?:json)?\s*([\s\S]*?)```/`) is fatally fragile: when a
212
+ * task/module prompt STRING embeds its own code fence (e.g. a ```bash example inside a task prompt),
213
+ * the non-greedy match stops at that EMBEDDED closing ```, truncating the block BEFORE the "tasks"
214
+ * key → a shape-valid-but-incomplete object → plan lost → raw JSON leaks into the chat bubble.
215
+ *
216
+ * Instead, scan for a balanced JSON object with string-awareness:
217
+ * - Pick a start index: the first `{` AT OR AFTER a ```json (or bare ```) fence opener if present,
218
+ * else the first `{` anywhere.
219
+ * - From that `{`, walk forward tracking brace depth AND JSON string state (an unescaped `"` toggles
220
+ * inString; a `\` inside a string escapes the next char). Count `{`/`}` only when NOT inString.
221
+ * Backticks/braces inside string values are thus ignored — embedded ```bash fences can't truncate.
222
+ * - When depth returns to 0, return the balanced `{`…`}` substring (trimmed).
223
+ * - If no balanced close is found, fall back to first-`{`…last-`}` (jsonrepair still gets a shot).
224
+ * - Return null if there is no `{` at all.
225
+ */
226
+ private extractJsonBlock;
227
+ /**
228
+ * Parse a JSON block that an LLM emitted. LLMs (DeepSeek especially, on Chinese content) routinely
229
+ * produce JSON with unescaped double quotes inside string values (e.g. 默认有"销售收入""其他收入"),
230
+ * trailing commas, etc. — strictly invalid, so JSON.parse throws and the whole plan is lost. Fall back
231
+ * to jsonrepair, which fixes these common LLM mistakes heuristically. Returns null only if even the
232
+ * repaired text won't parse.
233
+ */
234
+ private parseJsonLenient;
235
+ /**
236
+ * Build a canonicalizer that maps a leader-written agent identifier (which may be a display NAME like
237
+ * "小智"/"Claude" OR a canonical catalog id like "qlogicagent"/"claude") to the canonical catalog id.
238
+ *
239
+ * WHY: the leader prompt asks for `instances[].agentId` = "花名册里的 id", but leaders routinely emit
240
+ * the display NAME instead (e.g. agentId:"小智"). Downstream — the confirm pre-check
241
+ * (isAgentReady) and dispatch (buildExternalDescriptor) — both require a CANONICAL id; a name like
242
+ * "小智" makes isAgentReady fail (the qlogicagent always-ready short-circuit only matches the id, not
243
+ * the name) → leader-only Product wrongly blocked. Canonicalizing at parse time guarantees
244
+ * instances[].agentId is a catalog id regardless of what the leader wrote.
245
+ *
246
+ * The map is keyed by BOTH lowercased `id` AND lowercased `name` → canonical `id`, plus the explicit
247
+ * leader aliases "小智"→"qlogicagent" and "self"→"qlogicagent". Matching is EXACT (trim+lowercase) on
248
+ * id-or-name only — no partial/fuzzy matching, to avoid mis-mapping one agent onto another.
249
+ */
250
+ private buildAgentIdResolver;
251
+ /**
252
+ * Normalize every `task.assignee` so it ALWAYS equals an existing `instance.name` (the canonical
253
+ * convention the execution dispatch keys on — see agent-instance.ts `instances.find(i => i.name === …)`).
254
+ *
255
+ * Mutates `instances`/`tasks` in place. For each task:
256
+ * - assignee already === some instance.name → keep.
257
+ * - else assignee resolves to an agentId that some instance carries → repoint assignee to THAT
258
+ * instance's name (pick the first matching instance, preferring a non-leader/worker role when the
259
+ * same agentId backs several instances — leaders usually shouldn't also be doing leaf work).
260
+ * - else (assignee references an agent with no instance) → append a fresh worker instance
261
+ * `{ name: assignee, agentId: resolveAgentId(assignee) ?? assignee, role: "worker" }` and keep
262
+ * assignee = that new name (now it matches).
263
+ * Blank assignees are left untouched (confirm-time validation surfaces them).
264
+ */
265
+ private normalizeAssigneesToInstanceName;
144
266
  private tryParsePlan;
267
+ private tryParseAsk;
145
268
  private parseDagMutations;
146
269
  }
@@ -1,6 +1,6 @@
1
1
  import type { ProductConfirmParams, ProductPlan } from "../protocol/wire/acp-agent-management.js";
2
2
  import type { ProductOrchestrator } from "./agent-instance.js";
3
- import type { DagMutation, ProductPlanner } from "./product-planner.js";
3
+ import type { DagMutation, PlanningSession, ProductPlanner } from "./product-planner.js";
4
4
  export interface ProductLeaderCoordinator {
5
5
  consultLeader(productId: string, context: {
6
6
  progress: {
@@ -14,6 +14,22 @@ export interface ProductLeaderCoordinator {
14
14
  error: string;
15
15
  }>;
16
16
  }): Promise<DagMutation[]>;
17
+ reviewTaskOutput(productId: string, review: {
18
+ taskId: string;
19
+ instruction: string;
20
+ acceptanceCriteria: string;
21
+ output: string;
22
+ /** Relative paths the worker created/changed in its worktree — evidence the text-only judge
23
+ * cannot otherwise see. Lets the judge confirm the expected artifacts exist (lenient judging). */
24
+ changedFiles?: string[];
25
+ }): Promise<{
26
+ pass: boolean;
27
+ feedback?: string;
28
+ }>;
29
+ /** Snapshot the leader's PlanningSession for checkpoint persistence (durable execution). */
30
+ serializeSession(productId: string): PlanningSession | null;
31
+ /** Restore the leader's PlanningSession from a checkpoint (crash/resume recovery). */
32
+ restoreSession(data: PlanningSession): void;
17
33
  }
18
34
  export declare class ProductRunCoordinator {
19
35
  private planner;
@@ -6,6 +6,9 @@ export declare function findGitRoot(cwd: string): Promise<string | null>;
6
6
  /** Create an isolated git worktree. Returns the worktree path. */
7
7
  export declare function createWorktree(gitRoot: string, name: string, baseBranch?: string): Promise<string>;
8
8
  export declare function getWorktreeDiff(worktreePath: string): Promise<string>;
9
+ /** List the relative paths of files changed in a worktree (tracked diff vs HEAD + untracked).
10
+ * Used to surface "produced files" on a Product task before the worktree is torn down. */
11
+ export declare function listWorktreeChangedFiles(worktreePath: string): Promise<string[]>;
9
12
  /** Copy the changed files from a task worktree back into the product workspace. */
10
13
  export declare function materializeWorktreeChanges(worktreePath: string, targetRoot: string): Promise<void>;
11
14
  /** Remove a git worktree. */
@@ -10,6 +10,8 @@
10
10
  * - Cooldown: prevents rapid-fire creation within a session
11
11
  */
12
12
  import { MAX_SKILLS_PER_PROJECT, MAX_SKILLS_GLOBAL } from "../runtime/config/tunable-defaults.js";
13
+ import type { SkillInstruction } from "../contracts/turn-event.js";
14
+ export type { SkillCreateInstruction, SkillImproveInstruction, SkillInstruction, } from "../contracts/turn-event.js";
13
15
  export { MAX_SKILLS_PER_PROJECT, MAX_SKILLS_GLOBAL };
14
16
  export interface SkillTurnResult {
15
17
  ok: boolean;
@@ -26,25 +28,6 @@ export interface SkillTurnResult {
26
28
  /** Skill name if an existing skill was used */
27
29
  existingSkillName?: string | null;
28
30
  }
29
- export interface SkillCreateInstruction {
30
- type: "skill.create";
31
- /** Suggested skill name derived from tool usage pattern */
32
- suggestedName: string;
33
- /** Short description of what the skill does */
34
- description: string;
35
- /** Tool names involved */
36
- tools: string[];
37
- /** Number of orchestration steps */
38
- stepCount: number;
39
- }
40
- export interface SkillImproveInstruction {
41
- type: "skill.improve";
42
- /** Existing skill to improve */
43
- skillName: string;
44
- /** Reason for improvement */
45
- reason: string;
46
- }
47
- export type SkillInstruction = SkillCreateInstruction | SkillImproveInstruction;
48
31
  /**
49
32
  * Reset cooldown state (for testing).
50
33
  */
@@ -80,6 +80,16 @@ export declare class SoloEvaluator {
80
80
  * Creates worktrees, spawns agents in parallel, waits for completion, then evaluates.
81
81
  */
82
82
  start(params: SoloStartParams): Promise<string>;
83
+ /**
84
+ * Ensure the agent's ACP process is alive in its worktree, spawning it if absent. Used by the
85
+ * initial run AND by follow-up messages: the watchdog reaps idle competitors after the race, so a
86
+ * follow-up almost always arrives after the process is gone. The worktree (its files) is the durable
87
+ * state, so re-spawning there lets follow-ups keep working for the whole session — not just in the
88
+ * brief window before reaping. Self-agent gets the worktree-workdir + lean env (see runOne notes):
89
+ * QLOGICAGENT_WORKTREE_WORKDIR anchors writes to the worktree; QLOGICAGENT_SOLO_LEAN drops media
90
+ * tools so it matches the external coding CLIs and won't wander into 图像生成 on a code task.
91
+ */
92
+ private ensureAgentRunning;
83
93
  /**
84
94
  * Send a follow-up message to a specific agent within a solo session.
85
95
  * Agent must be in "idle" or "completed" state.
@@ -28,6 +28,10 @@ export interface SpecChatDeps {
28
28
  askUser: (questions: AskUserQuestion[], signal?: AbortSignal) => Promise<Record<string, string> | null>;
29
29
  log: AgentLogger;
30
30
  parentSignal?: AbortSignal;
31
+ /** Per-phase progress for the UI. A round is a blocking RPC that otherwise streams nothing back, so
32
+ * the handler relays these labels (solo.specProgress) to replace the frozen "思考中" with the real
33
+ * phase (分析 → 确认 → 拟定). Best-effort: never throws into the round. */
34
+ onPhase?: (phase: string) => void;
31
35
  }
32
36
  /** R3 多轮对话式 spec:agent 通过此工具产出/更新结构化规格(类比 plan_mode 的 plan 入参)。 */
33
37
  export declare const SET_SPEC_TOOL_NAME = "set_spec";
@@ -1,41 +1,40 @@
1
- /**
2
- * n8n workflow JSON import — read-format-only translator (plan M5 §2.1: "导入 n8n workflow JSON
3
- * (读格式,不打包其代码)"), deepened for IT-11 (spec D35).
4
- *
5
- * Converts an n8n workflow export (its public JSON shape: `nodes` + `connections`) into our own
6
- * WorkflowDef. This reads n8n's data FORMAT only — it links/embeds NONE of n8n's runtime code, so
7
- * the SUL licensing concern (plan §2.1 / risk register) does not apply.
8
- *
9
- * Error model (IT-11): STRUCTURAL problems (malformed JSON, duplicate/missing node names, dangling
10
- * connections) stay fail-loud — the graph identity itself is broken, nothing useful survives.
11
- * SEMANTIC gaps (unmapped node type, inconvertible expression, Code-node JS) DEGRADE EXPLICITLY:
12
- * the node lands as kind "manual" (its executor throws at run time — never silently passes
13
- * through), the original n8n type/params are preserved for the human, and every degradation is
14
- * itemized in the returned ConversionReport. Nothing is silently dropped; no JS is ever executed
15
- * (D6 hard line — n8n Code nodes are flagged manual, not emulated).
16
- *
17
- * Credentials: n8n nodes carry `credentials: {type: {id,name}}` references. The secrets are NOT
18
- * in the export — we extract them as CredentialRequirement entries (mapped to vault types, D29)
19
- * so the import UI can walk the user through re-binding.
20
- */
21
1
  import type { WorkflowDef } from "./node-schema.js";
2
+ export interface N8nImportOptions {
3
+ strictTemplates?: boolean;
4
+ }
22
5
  export interface N8nNodeReport {
23
6
  id: string;
24
7
  n8nType: string;
25
- /** converted=faithful; partial=landed but params need attention; manual=placeholder node; skipped=annotation dropped. */
26
- outcome: "converted" | "partial" | "manual" | "skipped";
8
+ outcome: "converted" | "partial" | "manual" | "skipped" | "unsupported";
27
9
  notes: string[];
28
10
  }
29
11
  export interface N8nCredentialRequirement {
30
12
  nodeId: string;
31
13
  n8nCredentialType: string;
32
- /** n8n-side display name of the credential (helps the user recognize which secret to re-create). */
33
14
  label?: string;
34
- /** Suggested vault credential type (D29). */
35
15
  suggestedVaultType: string;
36
16
  }
17
+ export interface N8nBindingRequirement {
18
+ models: Array<{
19
+ nodeId: string;
20
+ n8nCredentialType: string;
21
+ modelPurpose: string;
22
+ label?: string;
23
+ }>;
24
+ agents: Array<{
25
+ nodeId: string;
26
+ agentId?: string;
27
+ fallback: boolean;
28
+ label?: string;
29
+ }>;
30
+ connections: Array<{
31
+ nodeId: string;
32
+ n8nCredentialType: string;
33
+ connectionType: string;
34
+ label?: string;
35
+ }>;
36
+ }
37
37
  export interface N8nConversionReport {
38
- /** full=everything faithful; partial=some degradations; manual=at least one manual placeholder. */
39
38
  status: "full" | "partial" | "manual";
40
39
  nodes: N8nNodeReport[];
41
40
  expressions: {
@@ -48,6 +47,7 @@ export interface N8nConversionReport {
48
47
  }>;
49
48
  };
50
49
  credentials: N8nCredentialRequirement[];
50
+ bindings: N8nBindingRequirement;
51
51
  notes: string[];
52
52
  }
53
53
  export interface N8nImportResult {
@@ -55,14 +55,8 @@ export interface N8nImportResult {
55
55
  def: WorkflowDef;
56
56
  report: N8nConversionReport;
57
57
  }
58
- /** Thrown when an n8n workflow is STRUCTURALLY untranslatable. Carries every problem found. */
59
58
  export declare class N8nImportError extends Error {
60
59
  readonly errors: string[];
61
60
  constructor(errors: string[]);
62
61
  }
63
- /**
64
- * Convert an n8n workflow (a JSON string or already-parsed object) into a WorkflowDef + report.
65
- * The returned def is NOT yet graph-validated — pass it to `validateWorkflowDef` / a controller
66
- * write path, which is the single existing invariant gate.
67
- */
68
- export declare function convertN8nWorkflow(input: string | unknown, workflowId: string): N8nImportResult;
62
+ export declare function convertN8nWorkflow(input: string | unknown, workflowId: string, opts?: N8nImportOptions): N8nImportResult;
@@ -0,0 +1,5 @@
1
+ export declare const N8N_TEMPLATE_TYPE_MAP: Record<string, string>;
2
+ export declare function isModelCredentialType(type: string): boolean;
3
+ export declare function isAgentKind(kind: string): boolean;
4
+ export declare function modelPurposeForCredential(type: string): string;
5
+ export declare function suggestConnectionType(n8nType: string, credentialType: string): string;
@@ -7,12 +7,25 @@
7
7
  * engine stays a pure executor (plan D12/D13).
8
8
  */
9
9
  import type { NodeExecutor } from "./node-schema.js";
10
+ /**
11
+ * Node kinds whose builtin executor is an import-only stub a host is meant to replace.
12
+ * installHostExecutors overrides ONLY these when already present; any other
13
+ * pre-registered kind is kept. Single source of the "rebindable kind" rule.
14
+ */
15
+ export declare const REBINDABLE_NODE_KINDS: Set<string>;
10
16
  export declare class NodeRegistry {
11
17
  private executors;
12
18
  constructor(includeBuiltins?: boolean);
13
19
  register(kind: string, executor: NodeExecutor): void;
14
20
  /** Replace an existing executor (e.g. host overrides a built-in). Must already exist. */
15
21
  override(kind: string, executor: NodeExecutor): void;
22
+ /**
23
+ * Wire host-backed executors — the single source of the host-wiring rule used by the
24
+ * runtime, the gateway handler, and tests. Absent kinds are registered; an already-present
25
+ * rebindable kind (agentBinding/modelBinding, whose builtin is an import-only stub) is
26
+ * overridden; any other already-present kind is kept (caller's pre-registration wins).
27
+ */
28
+ installHostExecutors(executors: Record<string, NodeExecutor>): void;
16
29
  has(kind: string): boolean;
17
30
  get(kind: string): NodeExecutor;
18
31
  kinds(): string[];
@@ -115,6 +115,8 @@ export interface ExecutorContext {
115
115
  export interface ExecutorHost {
116
116
  /** Run an agent turn. Returns the agent's structured output as DataItem(s). */
117
117
  runAgent(req: AgentHostRequest): Promise<DataItem[]>;
118
+ /** Run the currently configured workflow/text model. The host resolves provider/API key/model. */
119
+ runModel?(req: ModelHostRequest): Promise<DataItem[]>;
118
120
  /** Invoke a qlogicagent tool by name. */
119
121
  invokeTool(req: ToolHostRequest): Promise<DataItem[]>;
120
122
  /** Perform an HTTP request (credentials resolved host-side). */
@@ -150,6 +152,14 @@ export interface AgentHostRequest {
150
152
  input: DataItem[];
151
153
  signal?: AbortSignal;
152
154
  }
155
+ export interface ModelHostRequest {
156
+ prompt: string;
157
+ modelHint?: string;
158
+ temperature?: number;
159
+ maxTokens?: number;
160
+ input: DataItem[];
161
+ signal?: AbortSignal;
162
+ }
153
163
  export interface ToolHostRequest {
154
164
  tool: string;
155
165
  args: Record<string, unknown>;
@@ -7,7 +7,7 @@
7
7
  * callback. Tool invocation goes straight through the single-source-of-truth tool registry
8
8
  * (`findTool`). fail-loud everywhere: unknown tool, missing channel host, or any rejection throws.
9
9
  */
10
- import type { RuntimeToolContract } from "../../runtime/ports/index.js";
10
+ import type { LLMTransport, RuntimeToolContract } from "../../runtime/ports/index.js";
11
11
  import { type DataItem } from "./data-item.js";
12
12
  import type { ExecutorHost, ToolHostRequest, MemoryHostRequest, SubworkflowHostRequest, ApprovalHostRequest, WebhookWaitHostRequest } from "./node-schema.js";
13
13
  /** Injected boundary capabilities — supplied by the handler host that owns the real runners. */
@@ -18,6 +18,12 @@ export interface QlaExecutorHostDeps {
18
18
  prompt: string;
19
19
  signal?: AbortSignal;
20
20
  }) => Promise<string>;
21
+ /** Resolve the owner's configured Settings -> Model text model. */
22
+ resolveClientForPurpose?: (purpose: "textGeneration") => {
23
+ transport: LLMTransport;
24
+ apiKey: string;
25
+ model: string;
26
+ } | null;
21
27
  /** Invoke an MCP server tool through the real MCP bridge. */
22
28
  invokeMcp: (req: {
23
29
  server: string;
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import type { ChatMessage, LocalizedToolText, ToolCapabilityCategory } from "./wire/chat-types.js";
10
10
  import type { AgentDescriptor, AgentConfig, GatewayRpcMethodMap, RpcProjectInfo, RpcProjectType, RpcProjectStatus, SoloStatus, ProductStatus, ProductSummary } from "./wire/index.js";
11
- import type { AgentsScanParams, AgentsConfigParams, AgentsSetConfigParams, AgentsGetConfigParams, AgentsRemoveConfigParams, AgentsSetGatewayParams, SoloStartParams, SoloIdParams, SoloSelectParams, SoloDeleteParams, SoloMessageParams, SoloEvaluateParams, SoloEvaluation, ProductCreateParams, ProductPlanParams, ProductPlan, ProductConfirmParams, ProductMessageParams, ProductIdParams, ProductDeleteParams } from "./wire/acp-agent-management.js";
11
+ import type { AgentsScanParams, AgentsConfigParams, AgentsSetConfigParams, AgentsGetConfigParams, AgentsRemoveConfigParams, AgentsSetGatewayParams, SoloStartParams, SoloIdParams, SoloSelectParams, SoloDeleteParams, SoloMessageParams, SoloEvaluateParams, SoloEvaluation, ProductCreateParams, ProductPlanParams, ProductPlan, ProductConfirmParams, ProductMessageParams, ProductIdParams, ProductDeleteParams, ProductReplayParams } from "./wire/acp-agent-management.js";
12
12
  export interface InitializeParams {
13
13
  protocolVersion: string;
14
14
  host?: {
@@ -1048,6 +1048,13 @@ export interface RpcMethodMap {
1048
1048
  ok: true;
1049
1049
  };
1050
1050
  };
1051
+ "product.replay": {
1052
+ params: ProductReplayParams;
1053
+ result: {
1054
+ productId: string;
1055
+ ok: true;
1056
+ };
1057
+ };
1051
1058
  "project.create": {
1052
1059
  params: ProjectCreateParams;
1053
1060
  result: ProjectCreateResult;
@@ -6,4 +6,4 @@
6
6
  * This file re-exports the wire types.
7
7
  * Internal consumers import from this file — zero churn.
8
8
  */
9
- export type { AgentSource, AgentsErrorNotification, AgentsStatusNotification, ArtifactType, MediaResultType, MemoryDecayCompletedNotification, MemoryUpdatedNotification, NotificationMethod, NotificationMethodMap, NotificationThreadItem, PermissionRuleUpdatedNotification, PlanInterruptedNotification, PongNotification, ProductBudgetUpdateNotification, ProductBudgetWarningNotification, ProductCheckpointedNotification, ProductCompletedNotification, ProductDagTopologyNotification, ProductPlanFailedNotification, ProductPlanningDeltaNotification, ProductPlanReadyNotification, ProductTaskCompletedNotification, ProductTaskFailedNotification, ProductTaskOutputDeltaNotification, ProductTaskStartedNotification, ProjectArchivedNotification, ProjectCreatedNotification, ProjectDeletedNotification, ProjectRenamedNotification, ProjectSwitchedNotification, ProjectUnarchivedNotification, SessionInfoNotification, SoloAgentDeltaNotification, SoloAgentUsageNotification, SoloEvaluationNotification, SoloProgressNotification, TeamMemberNotification, ToolApprovalRequestNotification, TurnAnnotationsNotification, TurnArtifactNotification, TurnAskUserNotification, TurnDeltaNotification, TurnEndNotification, TurnErrorNotification, TurnExecProgressNotification, TurnHeartbeatNotification, TurnMediaPersistedNotification, TurnMediaProgressNotification, TurnMediaResultNotification, TurnPlanUpdateNotification, TurnReasoningDeltaNotification, TurnRecoveryNotification, TurnSidechainCompletedNotification, TurnSidechainStartedNotification, TurnSkillInstructionNotification, TurnStartNotification, TurnSubagentDeltaNotification, TurnSuggestionsNotification, TurnTaskUpdatedNotification, TurnTodosUpdatedNotification, TurnToolBlockedNotification, TurnToolCallNotification, TurnToolResultNotification, TurnToolUseSummaryNotification, TurnUsageUpdateNotification, WireTokenUsage, } from "./wire/index.js";
9
+ export type { AgentSource, AgentsErrorNotification, AgentsStatusNotification, ArtifactType, MediaResultType, MemoryDecayCompletedNotification, MemoryUpdatedNotification, NotificationMethod, NotificationMethodMap, NotificationThreadItem, PermissionRuleUpdatedNotification, PlanInterruptedNotification, PongNotification, ProductAgentActivityNotification, ProductBudgetUpdateNotification, ProductBudgetWarningNotification, ProductCheckpointedNotification, ProductCompletedNotification, ProductDagTopologyNotification, ProductMembersNotification, ProductPlanFailedNotification, ProductPlanningDeltaNotification, ProductPlanReadyNotification, ProductTaskCompletedNotification, ProductTaskFailedNotification, ProductTaskOutputDeltaNotification, ProductTaskStartedNotification, ProjectArchivedNotification, ProjectCreatedNotification, ProjectDeletedNotification, ProjectRenamedNotification, ProjectSwitchedNotification, ProjectUnarchivedNotification, SessionInfoNotification, SoloAgentDeltaNotification, SoloAgentUsageNotification, SoloEvaluationNotification, SoloProgressNotification, TeamMemberNotification, ToolApprovalRequestNotification, TurnAnnotationsNotification, TurnArtifactNotification, TurnAskUserNotification, TurnDeltaNotification, TurnEndNotification, TurnErrorNotification, TurnExecProgressNotification, TurnHeartbeatNotification, TurnMediaPersistedNotification, TurnMediaProgressNotification, TurnMediaResultNotification, TurnPlanUpdateNotification, TurnReasoningDeltaNotification, TurnRecoveryNotification, TurnSidechainCompletedNotification, TurnSidechainStartedNotification, TurnSkillInstructionNotification, TurnStartNotification, TurnSubagentDeltaNotification, TurnSuggestionsNotification, TurnTaskUpdatedNotification, TurnTodosUpdatedNotification, TurnToolBlockedNotification, TurnToolCallNotification, TurnToolResultNotification, TurnToolUseSummaryNotification, TurnUsageUpdateNotification, WireTokenUsage, } from "./wire/index.js";