@multiclawcli/core 0.3.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/arch-design-reviewer.d.ts +4 -0
- package/dist/agents/architect.d.ts +4 -0
- package/dist/agents/backend-developer.d.ts +4 -0
- package/dist/agents/code-reviewer.d.ts +4 -0
- package/dist/agents/devops.d.ts +4 -0
- package/dist/agents/frontend-developer.d.ts +4 -0
- package/dist/agents/index.d.ts +26 -0
- package/dist/agents/leader.d.ts +4 -0
- package/dist/agents/product-manager.d.ts +4 -0
- package/dist/agents/reviewer.d.ts +4 -0
- package/dist/agents/tester.d.ts +4 -0
- package/dist/agents/ui-design-reviewer.d.ts +4 -0
- package/dist/agents/ui-designer.d.ts +4 -0
- package/dist/config/defineConfig.d.ts +2 -0
- package/dist/event/EventBus.d.ts +7 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +2207 -811
- package/dist/orchestrator/AgentRunner.d.ts +19 -0
- package/dist/orchestrator/ContextManager.d.ts +7 -0
- package/dist/orchestrator/Orchestrator.d.ts +109 -0
- package/dist/orchestrator/StageBuilder.d.ts +2 -0
- package/dist/providers/bridge.d.ts +29 -0
- package/dist/providers/catalog.d.ts +73 -0
- package/dist/providers/detect.d.ts +34 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/resolve.d.ts +26 -0
- package/dist/runtime/AcpRuntime.d.ts +17 -0
- package/dist/runtime/RuntimeBase.d.ts +6 -0
- package/dist/runtime/index.d.ts +12 -0
- package/dist/types/agent.d.ts +96 -0
- package/dist/types/config.d.ts +126 -0
- package/dist/types/event.d.ts +115 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/leader.d.ts +36 -0
- package/dist/types/runtime.d.ts +146 -0
- package/dist/utils/abort.d.ts +4 -0
- package/dist/utils/conversation.d.ts +29 -0
- package/dist/utils/errors.d.ts +16 -0
- package/dist/utils/json.d.ts +10 -0
- package/dist/utils/leaderDecision.d.ts +17 -0
- package/dist/utils/prompt.d.ts +1 -0
- package/dist/utils/resumePlan.d.ts +35 -0
- package/dist/utils/retry.d.ts +36 -0
- package/dist/utils/timeout.d.ts +1 -0
- package/dist/utils/toolSummary.d.ts +13 -0
- package/dist/utils/upstream.d.ts +69 -0
- package/package.json +18 -4
- package/src/agents/arch-design-reviewer.ts +0 -45
- package/src/agents/architect.ts +0 -72
- package/src/agents/backend-developer.ts +0 -54
- package/src/agents/code-reviewer.ts +0 -54
- package/src/agents/devops.ts +0 -59
- package/src/agents/frontend-developer.ts +0 -56
- package/src/agents/index.ts +0 -27
- package/src/agents/leader.ts +0 -37
- package/src/agents/product-manager.ts +0 -43
- package/src/agents/reviewer.ts +0 -47
- package/src/agents/tester.ts +0 -53
- package/src/agents/ui-design-reviewer.ts +0 -48
- package/src/agents/ui-designer.ts +0 -61
- package/src/config/defineConfig.ts +0 -4
- package/src/event/EventBus.ts +0 -19
- package/src/index.ts +0 -8
- package/src/orchestrator/AgentRunner.ts +0 -104
- package/src/orchestrator/ContextManager.ts +0 -11
- package/src/orchestrator/Orchestrator.ts +0 -180
- package/src/orchestrator/StageBuilder.ts +0 -30
- package/src/runtime/ClaudeRuntime.ts +0 -41
- package/src/runtime/RuntimeBase.ts +0 -7
- package/src/runtime/index.ts +0 -20
- package/src/types/agent.ts +0 -48
- package/src/types/config.ts +0 -26
- package/src/types/event.ts +0 -21
- package/src/types/index.ts +0 -4
- package/src/types/runtime.ts +0 -23
- package/src/utils/prompt.ts +0 -24
- package/src/utils/retry.ts +0 -24
- package/src/utils/timeout.ts +0 -16
- package/tsconfig.build.json +0 -9
- package/tsconfig.json +0 -5
- package/tsup.config.ts +0 -10
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { EventBus } from "../event/EventBus";
|
|
2
|
+
import type { AgentDefinition, AgentResult } from "../types/agent";
|
|
3
|
+
import type { MultiClawConfig } from "../types/config";
|
|
4
|
+
import type { ContextManager } from "./ContextManager";
|
|
5
|
+
export declare class AgentRunner {
|
|
6
|
+
private eventBus;
|
|
7
|
+
private contextManager;
|
|
8
|
+
private globalWorkDir;
|
|
9
|
+
private config;
|
|
10
|
+
constructor(eventBus: EventBus, contextManager: ContextManager, globalWorkDir: string, config: MultiClawConfig);
|
|
11
|
+
run(agent: AgentDefinition, signal?: AbortSignal): Promise<AgentResult>;
|
|
12
|
+
/**
|
|
13
|
+
* Publish one chunk of agent output.
|
|
14
|
+
*
|
|
15
|
+
* `kind` is omitted for text so the payload shape is unchanged for every
|
|
16
|
+
* consumer written before tool activity was surfaced.
|
|
17
|
+
*/
|
|
18
|
+
private emitOutput;
|
|
19
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { EventBus } from "../event/EventBus";
|
|
2
|
+
import type { MultiClawConfig, OrchestrationPreview, OrchestratorResult } from "../types/config";
|
|
3
|
+
export declare class Orchestrator {
|
|
4
|
+
private config;
|
|
5
|
+
readonly eventBus: EventBus;
|
|
6
|
+
private contextManager;
|
|
7
|
+
private runner;
|
|
8
|
+
private workDir;
|
|
9
|
+
constructor(config: MultiClawConfig);
|
|
10
|
+
preview(options?: {
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
}): Promise<OrchestrationPreview>;
|
|
13
|
+
run(options?: {
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}): Promise<OrchestratorResult>;
|
|
16
|
+
private stageInfos;
|
|
17
|
+
/**
|
|
18
|
+
* Order the agents into stages, degrading to declaration order if the graph is
|
|
19
|
+
* broken.
|
|
20
|
+
*
|
|
21
|
+
* `buildStages` throws on a missing dependency and on a cycle. Letting that
|
|
22
|
+
* escape would reject `run()` before `orchestration:complete` is emitted, so
|
|
23
|
+
* the caller sees an unhandled rejection instead of a structured failure. A
|
|
24
|
+
* bad ordering is not a reason to run nothing.
|
|
25
|
+
*/
|
|
26
|
+
private buildStagesOrFallback;
|
|
27
|
+
/**
|
|
28
|
+
* Drop last run's task plan before the architect gets a chance to write one.
|
|
29
|
+
*
|
|
30
|
+
* The console runs every turn against the same workspace, so the plan file
|
|
31
|
+
* survives between turns. If a turn's architect fails to write a new one,
|
|
32
|
+
* `applyTaskPlan` would silently re-apply the previous turn's titles, scopes
|
|
33
|
+
* and dependencies to a completely different requirement.
|
|
34
|
+
*/
|
|
35
|
+
private clearStaleTaskPlan;
|
|
36
|
+
/**
|
|
37
|
+
* Decide what this turn is: a pipeline, an answer, or a question.
|
|
38
|
+
*
|
|
39
|
+
* Only the leader can answer that, so without one the configured team is the
|
|
40
|
+
* whole story. With one, its prose output is *not* a failure mode to be papered
|
|
41
|
+
* over by running everybody — a leader that answers a greeting has done its
|
|
42
|
+
* job, and that is what `message` records.
|
|
43
|
+
*/
|
|
44
|
+
private resolveTurn;
|
|
45
|
+
/**
|
|
46
|
+
* The configured team, as copies.
|
|
47
|
+
*
|
|
48
|
+
* `applyTaskPlan` writes `taskTitle` / `dependsOn` / `agentScope` onto whatever
|
|
49
|
+
* objects it is handed. The console reuses a single config across turns, so
|
|
50
|
+
* returning the config's own objects would leak turn 1's dependency graph into
|
|
51
|
+
* turn 2 — the exact cross-turn contamination `clearStaleTaskPlan` exists to
|
|
52
|
+
* prevent, but for the in-memory fields rather than the file.
|
|
53
|
+
*/
|
|
54
|
+
private configuredAgents;
|
|
55
|
+
/**
|
|
56
|
+
* Narrow the configured team to the ids `namedBy` asked for.
|
|
57
|
+
*
|
|
58
|
+
* Always a subset: an id that is not in the config is reported and dropped
|
|
59
|
+
* rather than added, so a typo in a prompt cannot conjure an agent that has no
|
|
60
|
+
* definition behind it.
|
|
61
|
+
*
|
|
62
|
+
* `namedBy` labels the warning. A resume names agents too — with no leader in
|
|
63
|
+
* the run at all — so blaming "the leader" for a bad resumed id would send the
|
|
64
|
+
* reader looking in the wrong place.
|
|
65
|
+
*/
|
|
66
|
+
private selectAgents;
|
|
67
|
+
private runStage;
|
|
68
|
+
/**
|
|
69
|
+
* Whether `agent` owns task decomposition.
|
|
70
|
+
*
|
|
71
|
+
* The explicit `role` is the source of truth, so a config can name its planner
|
|
72
|
+
* anything. The id `"architect"` is kept as a fallback so every config written
|
|
73
|
+
* before `role` existed keeps working unchanged.
|
|
74
|
+
*/
|
|
75
|
+
private isPlanner;
|
|
76
|
+
private applyTaskPlan;
|
|
77
|
+
/**
|
|
78
|
+
* The `requirement` field for a result, present only when the caller set one.
|
|
79
|
+
*
|
|
80
|
+
* Spread into every result builder so all three outcomes carry it the same
|
|
81
|
+
* way: a completion event doubles as the report a resume driver reads back,
|
|
82
|
+
* and a requirement that never reaches the report cannot be resumed.
|
|
83
|
+
*/
|
|
84
|
+
private requirementField;
|
|
85
|
+
/**
|
|
86
|
+
* The `selectionReason` field, present only when the leader explained itself.
|
|
87
|
+
*
|
|
88
|
+
* Omitted rather than sent as `undefined`/`""` so a run without an
|
|
89
|
+
* explanation stays byte-identical to one from before the field existed.
|
|
90
|
+
*/
|
|
91
|
+
private reasonField;
|
|
92
|
+
/**
|
|
93
|
+
* Close out a turn the leader answered rather than planned.
|
|
94
|
+
*
|
|
95
|
+
* `success: true` on purpose: the user asked something and got an answer. What
|
|
96
|
+
* keeps that from reading as a completed pipeline is `reply`, which the console
|
|
97
|
+
* uses to say "answered" instead of "done".
|
|
98
|
+
*/
|
|
99
|
+
private finishWithMessage;
|
|
100
|
+
private warn;
|
|
101
|
+
/**
|
|
102
|
+
* Close out a turn that scheduled no agents.
|
|
103
|
+
*
|
|
104
|
+
* Reported as a failure rather than a no-op: the user asked for work, and the
|
|
105
|
+
* only honest outcome is to say that none was done. Running the whole team
|
|
106
|
+
* instead would contradict the leader's explicit choice.
|
|
107
|
+
*/
|
|
108
|
+
private finishEmpty;
|
|
109
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ACP bridges that multiclaw bundles and resolves from its own `node_modules`
|
|
3
|
+
* rather than requiring the user to install them globally.
|
|
4
|
+
*
|
|
5
|
+
* Key = the binary name used in an agent's `command`; value = the npm package
|
|
6
|
+
* that provides it. `opencode` is deliberately absent: it speaks ACP natively,
|
|
7
|
+
* so it *is* the user's agent and is installed by the user.
|
|
8
|
+
*/
|
|
9
|
+
export declare const BRIDGE_PACKAGES: Record<string, string>;
|
|
10
|
+
/** True when `command` names an executable file on PATH. */
|
|
11
|
+
export declare function resolvesOnPath(command: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Resolve a bundled bridge binary to an absolute path inside multiclaw's
|
|
14
|
+
* installed `node_modules`. Returns null when `command` is not a bridge we
|
|
15
|
+
* bundle (e.g. a user-supplied binary such as `opencode`).
|
|
16
|
+
*
|
|
17
|
+
* This lets multiclaw drive the ACP bridge without it being on the user's PATH:
|
|
18
|
+
* the user only installs their own agent (`claude` / `codex` / `opencode`), and
|
|
19
|
+
* multiclaw supplies the thin bridge in front of it.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveBridgeBinary(command: string): string | null;
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the executable multiclaw should spawn for `command`.
|
|
24
|
+
*
|
|
25
|
+
* Prefers the user's own install on PATH (this is also what the test suite
|
|
26
|
+
* relies on — fake binaries are placed on PATH), and falls back to a bridge
|
|
27
|
+
* multiclaw bundles. Returns null when neither is available.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveExecutable(command: string): string | null;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { AgentTask } from "../types/runtime";
|
|
2
|
+
export type ProviderId = "claude" | "opencode" | "codex" | "cursor" | (string & {});
|
|
3
|
+
export type ModelTier = "strong" | "balanced" | "fast";
|
|
4
|
+
export interface ProviderModel {
|
|
5
|
+
id: string;
|
|
6
|
+
label: string;
|
|
7
|
+
tier?: ModelTier;
|
|
8
|
+
/** True when this model is the default for its tier within this provider. */
|
|
9
|
+
defaultForTier?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* How a provider is told which model to run.
|
|
13
|
+
*
|
|
14
|
+
* `"arg"` used to be a member here, but nothing in `AcpRuntime` ever implemented
|
|
15
|
+
* it — so a provider that declared it silently ran with its own default. It is
|
|
16
|
+
* gone rather than kept as a dead branch: re-introducing it means also
|
|
17
|
+
* implementing the `arg` path in `AcpRuntime`, and this note is the cost the
|
|
18
|
+
* next person to add it back has to pay.
|
|
19
|
+
*/
|
|
20
|
+
export type ModelSelectionMode = "config-option" | "none";
|
|
21
|
+
export interface ProviderSpec {
|
|
22
|
+
id: ProviderId;
|
|
23
|
+
label: string;
|
|
24
|
+
/** Binary to spawn. */
|
|
25
|
+
command: string;
|
|
26
|
+
/** Arguments after the binary. */
|
|
27
|
+
args: string[];
|
|
28
|
+
/** Additional binary names that resolve to this provider (for detection). */
|
|
29
|
+
aliases?: string[];
|
|
30
|
+
/**
|
|
31
|
+
* Build the `_meta` payload for a session-defining request.
|
|
32
|
+
* Returns `undefined` when there is nothing to say — the role prompt
|
|
33
|
+
* then falls back to a prompt prefix.
|
|
34
|
+
*/
|
|
35
|
+
meta?: (task: AgentTask) => Record<string, unknown> | undefined;
|
|
36
|
+
/** Whether this provider honours a tool allowlist at all. */
|
|
37
|
+
tools: boolean;
|
|
38
|
+
/** How model selection is communicated to the agent. */
|
|
39
|
+
modelSelection: ModelSelectionMode;
|
|
40
|
+
/** Models offered by this provider. */
|
|
41
|
+
models: ProviderModel[];
|
|
42
|
+
/** Fallback when no tier or explicit model is configured. */
|
|
43
|
+
defaultModel: string;
|
|
44
|
+
install: {
|
|
45
|
+
hint: string;
|
|
46
|
+
url?: string;
|
|
47
|
+
};
|
|
48
|
+
/** Auth prerequisite — shown as a hint, not a hard gate (v1). */
|
|
49
|
+
auth: {
|
|
50
|
+
kind: "ambient" | "login" | "api-key" | "none";
|
|
51
|
+
hint: string;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* When the binary name is ambiguous (e.g. cursor's `agent`),
|
|
55
|
+
* use `--version` output to confirm identity. Mandatory for generic names.
|
|
56
|
+
*/
|
|
57
|
+
confirm?: (versionOutput: string) => boolean;
|
|
58
|
+
}
|
|
59
|
+
export declare const PROVIDERS: readonly ProviderSpec[];
|
|
60
|
+
/** Lookup a provider by its id. */
|
|
61
|
+
export declare function specForProvider(id: string): ProviderSpec | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Lookup a provider by the binary name it is launched with.
|
|
64
|
+
* Keys on basename (strips paths and Windows suffixes) so
|
|
65
|
+
* `/opt/bin/claude-agent-acp` and `claude-agent-acp.exe` both hit.
|
|
66
|
+
*/
|
|
67
|
+
export declare function specForCommand(command: string): ProviderSpec | undefined;
|
|
68
|
+
/** All provider ids known to the catalog. */
|
|
69
|
+
export declare function providerIds(): string[];
|
|
70
|
+
/** All commands (primary + aliases) that map to a provider. */
|
|
71
|
+
export declare function providerCommands(): string[];
|
|
72
|
+
/** Resolve a tier to a concrete model id for a given provider. */
|
|
73
|
+
export declare function tierModel(spec: ProviderSpec, tier: ModelTier): string | undefined;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type ProviderStatus = "present" | "missing";
|
|
2
|
+
/**
|
|
3
|
+
* Where the executable for a present provider came from.
|
|
4
|
+
*
|
|
5
|
+
* `path` is the user's own install on PATH — the expected case. `bundled` means
|
|
6
|
+
* multiclaw's own `node_modules` supplied the bridge, so the provider works
|
|
7
|
+
* without the bridge being installed globally; that is worth telling the user,
|
|
8
|
+
* because "present" then says nothing about what they have installed.
|
|
9
|
+
*/
|
|
10
|
+
export type ProviderSource = "path" | "bundled";
|
|
11
|
+
export interface DetectedProvider {
|
|
12
|
+
id: string;
|
|
13
|
+
label: string;
|
|
14
|
+
command: string;
|
|
15
|
+
status: ProviderStatus;
|
|
16
|
+
version?: string;
|
|
17
|
+
note?: string;
|
|
18
|
+
/** How the executable resolves. Absent for a missing provider. */
|
|
19
|
+
source?: ProviderSource;
|
|
20
|
+
/** Absolute path actually spawned, set only for a bundled bridge. */
|
|
21
|
+
resolvedPath?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Discover which providers are installed on this machine.
|
|
25
|
+
*
|
|
26
|
+
* Availability comes from PATH lookups (fast, no spawn). When
|
|
27
|
+
* `withVersion` is true, ambiguous binary names (e.g. cursor's `agent`)
|
|
28
|
+
* are confirmed via `--version` output.
|
|
29
|
+
*/
|
|
30
|
+
export declare function detectProviders(opts?: {
|
|
31
|
+
withVersion?: boolean;
|
|
32
|
+
}): Promise<DetectedProvider[]>;
|
|
33
|
+
/** Just the ids of providers that are present. */
|
|
34
|
+
export declare function presentProviders(detected: DetectedProvider[]): string[];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { BRIDGE_PACKAGES, resolveBridgeBinary, resolveExecutable, resolvesOnPath, } from "./bridge";
|
|
2
|
+
export { type ModelSelectionMode, type ModelTier, PROVIDERS, type ProviderId, type ProviderModel, type ProviderSpec, providerCommands, providerIds, specForCommand, specForProvider, tierModel, } from "./catalog";
|
|
3
|
+
export { type DetectedProvider, detectProviders, type ProviderSource, type ProviderStatus, presentProviders, } from "./detect";
|
|
4
|
+
export { resolveAgentRuntime, resolveArgs, resolveCommand, resolveModel, resolveProvider, } from "./resolve";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { AgentDefinition } from "../types/agent";
|
|
2
|
+
import type { MultiClawConfig } from "../types/config";
|
|
3
|
+
import { type ProviderSpec } from "./catalog";
|
|
4
|
+
/** Resolve the provider id for an agent, falling back through config defaults. */
|
|
5
|
+
export declare function resolveProvider(agent: AgentDefinition, config: MultiClawConfig): string;
|
|
6
|
+
/** Resolve the launch command for an agent. */
|
|
7
|
+
export declare function resolveCommand(agent: AgentDefinition, config: MultiClawConfig): string;
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the launch arguments for an agent.
|
|
10
|
+
*
|
|
11
|
+
* Paired with {@link resolveCommand}: the catalog carries per-provider args
|
|
12
|
+
* (`opencode acp` needs `["acp"]`, the bundled bridges need `[]`), so leaving
|
|
13
|
+
* `args` undefined would let the runtime fall back to its `["acp"]` default and
|
|
14
|
+
* launch e.g. `claude-agent-acp acp`. Returns undefined for a truly custom
|
|
15
|
+
* command so the runtime's default still applies.
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveArgs(agent: AgentDefinition, config: MultiClawConfig): string[] | undefined;
|
|
18
|
+
/** Resolve the model id an agent will actually run with. */
|
|
19
|
+
export declare function resolveModel(agent: AgentDefinition, config: MultiClawConfig): string | undefined;
|
|
20
|
+
/** Convenience: full resolution in one call. */
|
|
21
|
+
export declare function resolveAgentRuntime(agent: AgentDefinition, config: MultiClawConfig): {
|
|
22
|
+
provider: string;
|
|
23
|
+
command: string;
|
|
24
|
+
model: string | undefined;
|
|
25
|
+
spec: ProviderSpec | undefined;
|
|
26
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AgentOutput, AgentTask, RuntimeInfo, RuntimeQuery } from "../types/runtime";
|
|
2
|
+
import { RuntimeBase } from "./RuntimeBase";
|
|
3
|
+
/**
|
|
4
|
+
* Grace period between SIGTERM and SIGKILL when an agent will not stop.
|
|
5
|
+
*
|
|
6
|
+
* This is time a single attempt can still consume *after* its `timeout`: the
|
|
7
|
+
* inner timeout fires a SIGTERM, and a child that ignores it is not reaped until
|
|
8
|
+
* this grace elapses — the reject itself lands on the child's `close`. A caller
|
|
9
|
+
* that budgets for a whole retry sequence must therefore add this to the
|
|
10
|
+
* per-attempt timeout, or its "upper bound" is not one (see `retryBudgetMs`).
|
|
11
|
+
*/
|
|
12
|
+
export declare const KILL_ESCALATION_MS = 3000;
|
|
13
|
+
export declare class AcpRuntime extends RuntimeBase {
|
|
14
|
+
readonly name = "acp";
|
|
15
|
+
describe(options?: RuntimeQuery): Promise<RuntimeInfo>;
|
|
16
|
+
execute(task: AgentTask): Promise<AgentOutput>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AgentOutput, AgentRuntime, AgentTask, RuntimeInfo, RuntimeQuery } from "../types/runtime";
|
|
2
|
+
export declare abstract class RuntimeBase implements AgentRuntime {
|
|
3
|
+
abstract readonly name: string;
|
|
4
|
+
abstract describe(options?: RuntimeQuery): Promise<RuntimeInfo>;
|
|
5
|
+
abstract execute(task: AgentTask): Promise<AgentOutput>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AgentRuntime } from "../types/runtime";
|
|
2
|
+
import { AcpRuntime, KILL_ESCALATION_MS } from "./AcpRuntime";
|
|
3
|
+
declare class RuntimeRegistry {
|
|
4
|
+
private runtimes;
|
|
5
|
+
constructor();
|
|
6
|
+
register(r: AgentRuntime): void;
|
|
7
|
+
get(name: string): AgentRuntime;
|
|
8
|
+
has(name: string): boolean;
|
|
9
|
+
list(): string[];
|
|
10
|
+
}
|
|
11
|
+
export declare const runtimeRegistry: RuntimeRegistry;
|
|
12
|
+
export { AcpRuntime, KILL_ESCALATION_MS };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { AgentOutput } from "./runtime";
|
|
2
|
+
export type ToolName = "Read" | "Write" | "Edit" | "MultiEdit" | "Bash" | "Glob" | "Grep" | "WebFetch";
|
|
3
|
+
export interface AgentDefinition {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
icon?: string;
|
|
7
|
+
runtime?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Agent product (e.g. "claude", "opencode", "codex", "cursor").
|
|
10
|
+
* Distinct from `runtime` (the protocol, always "acp" today).
|
|
11
|
+
* When absent it is inferred from `command` or config defaults.
|
|
12
|
+
*/
|
|
13
|
+
provider?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Command to launch for this agent's runtime, when the runtime talks to an
|
|
16
|
+
* external process (e.g. ACP). Generic — "which binary to start", not a
|
|
17
|
+
* protocol detail — so a built-in runtime simply ignores it.
|
|
18
|
+
*/
|
|
19
|
+
command?: string;
|
|
20
|
+
/** Arguments for {@link command}. */
|
|
21
|
+
args?: string[];
|
|
22
|
+
model?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Map of provider ids (or the legacy alias "acp") to model names.
|
|
25
|
+
* Provider id is preferred; "acp" is kept for backward compatibility.
|
|
26
|
+
*/
|
|
27
|
+
models?: Partial<Record<string, string>>;
|
|
28
|
+
/**
|
|
29
|
+
* Model tier preference. Used when `model` and `models` are absent.
|
|
30
|
+
* The catalog maps each tier to a provider-specific model id.
|
|
31
|
+
*/
|
|
32
|
+
modelTier?: "strong" | "balanced" | "fast";
|
|
33
|
+
systemPrompt: string;
|
|
34
|
+
taskPrompt: string;
|
|
35
|
+
/**
|
|
36
|
+
* One-line role, for display. Every built-in agent declares one.
|
|
37
|
+
*
|
|
38
|
+
* Distinct from {@link taskTitle}, which the orchestrator fills in per turn
|
|
39
|
+
* from the leader's task plan — "what this agent was asked to do *this* run".
|
|
40
|
+
* A `description` is "what this agent is for", so it is the one that is still
|
|
41
|
+
* available before the first turn has been planned.
|
|
42
|
+
*/
|
|
43
|
+
description?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Marks the agent that owns task decomposition (writes task-plan.json).
|
|
46
|
+
* When absent, the orchestrator falls back to the id "architect" so every
|
|
47
|
+
* existing config keeps working unchanged.
|
|
48
|
+
*/
|
|
49
|
+
role?: "planner";
|
|
50
|
+
taskTitle?: string;
|
|
51
|
+
agentScope?: string;
|
|
52
|
+
agentPlan?: string;
|
|
53
|
+
tools?: ToolName[];
|
|
54
|
+
dependsOn?: string[];
|
|
55
|
+
timeout?: number;
|
|
56
|
+
retries?: number;
|
|
57
|
+
workDir?: string;
|
|
58
|
+
}
|
|
59
|
+
export type AgentStatus = "pending" | "running" | "retrying" | "success" | "failed"
|
|
60
|
+
/**
|
|
61
|
+
* The run was stopped by its AbortSignal rather than finishing or erroring.
|
|
62
|
+
* Distinct from `failed` so a Ctrl-C does not read as a crash, and so the
|
|
63
|
+
* roster can mark the agent stopped instead of broken.
|
|
64
|
+
*/
|
|
65
|
+
| "cancelled" | "skipped";
|
|
66
|
+
export interface AgentResult {
|
|
67
|
+
agentId: string;
|
|
68
|
+
agentName: string;
|
|
69
|
+
status: AgentStatus;
|
|
70
|
+
output: string;
|
|
71
|
+
duration: number;
|
|
72
|
+
attempts: number;
|
|
73
|
+
error?: string;
|
|
74
|
+
startTime: string;
|
|
75
|
+
endTime: string;
|
|
76
|
+
/** Model actually requested for this agent. */
|
|
77
|
+
model?: string;
|
|
78
|
+
/** Context-window usage the runtime reported; absent when it reported none. */
|
|
79
|
+
usage?: AgentOutput["usage"];
|
|
80
|
+
/** USD cost the runtime reported; absent when the provider does not price in USD. */
|
|
81
|
+
costUsd?: number;
|
|
82
|
+
/** Session the runtime ran under, when it reported one. */
|
|
83
|
+
sessionId?: string;
|
|
84
|
+
}
|
|
85
|
+
export interface SubTask {
|
|
86
|
+
id: string;
|
|
87
|
+
title: string;
|
|
88
|
+
scope: string;
|
|
89
|
+
plan?: string[];
|
|
90
|
+
dependsOn?: string[];
|
|
91
|
+
}
|
|
92
|
+
export interface TaskPlan {
|
|
93
|
+
projectName: string;
|
|
94
|
+
requirement: string;
|
|
95
|
+
tasks: SubTask[];
|
|
96
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { AgentDefinition } from "./agent";
|
|
2
|
+
import type { LeaderMessage } from "./leader";
|
|
3
|
+
/**
|
|
4
|
+
* One finished turn of a session, as dialogue the leader can read back.
|
|
5
|
+
*
|
|
6
|
+
* A requirement alone is not always interpretable: when the leader asked "which
|
|
7
|
+
* database?" and the user answered "Postgres", turn two's requirement is the
|
|
8
|
+
* bare word "Postgres". Paired with the turn that produced the question it is
|
|
9
|
+
* obvious; on its own it is not.
|
|
10
|
+
*/
|
|
11
|
+
export interface TurnRecord {
|
|
12
|
+
/** What the user asked for. */
|
|
13
|
+
requirement: string;
|
|
14
|
+
/** How the turn ended in words, when it ended that way. */
|
|
15
|
+
reply?: LeaderMessage;
|
|
16
|
+
}
|
|
17
|
+
export interface MultiClawConfig {
|
|
18
|
+
name: string;
|
|
19
|
+
workDir: string;
|
|
20
|
+
leader?: AgentDefinition;
|
|
21
|
+
agents: AgentDefinition[];
|
|
22
|
+
context?: Record<string, string>;
|
|
23
|
+
/**
|
|
24
|
+
* Earlier turns of this session, oldest first.
|
|
25
|
+
*
|
|
26
|
+
* Core has no notion of a session — the orchestrator is built fresh per turn —
|
|
27
|
+
* so whoever runs several turns in a row (the console) is the one that has to
|
|
28
|
+
* carry them. Rendered into the leader's prompt; a single-turn run leaves it
|
|
29
|
+
* unset and sees no conversation at all.
|
|
30
|
+
*/
|
|
31
|
+
history?: TurnRecord[];
|
|
32
|
+
/**
|
|
33
|
+
* Re-run a known set of agents instead of letting the leader route, continuing
|
|
34
|
+
* their sessions where one is known.
|
|
35
|
+
*
|
|
36
|
+
* Set by a resume/retry driver — the CLI's `--resume`, the console's `/retry` —
|
|
37
|
+
* which already knows which agents to redo. Like `history`, it is per-run state
|
|
38
|
+
* the caller carries: core has no session of its own, and a config that never
|
|
39
|
+
* resumes leaves it unset and behaves exactly as before.
|
|
40
|
+
*/
|
|
41
|
+
resume?: {
|
|
42
|
+
/** Agent ids to run, in the order they were originally selected. */
|
|
43
|
+
agents: string[];
|
|
44
|
+
/** agentId → session id, for agents whose session is worth continuing. */
|
|
45
|
+
sessions?: Record<string, string>;
|
|
46
|
+
};
|
|
47
|
+
logDir?: string;
|
|
48
|
+
continueOnError?: boolean;
|
|
49
|
+
maxConcurrency?: number;
|
|
50
|
+
useLeader?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Project-level defaults applied to every agent that does not override them.
|
|
53
|
+
* Keeps generated configs readable: one line instead of 12 repeated parameters.
|
|
54
|
+
*/
|
|
55
|
+
defaults?: {
|
|
56
|
+
provider?: string;
|
|
57
|
+
model?: string;
|
|
58
|
+
command?: string;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export interface OrchestrationPreview {
|
|
62
|
+
name: string;
|
|
63
|
+
requirement?: string;
|
|
64
|
+
totalAgents: number;
|
|
65
|
+
stages: import("./event").StageInfo[];
|
|
66
|
+
/** Present when the leader answered or asked instead of choosing a pipeline. */
|
|
67
|
+
reply?: LeaderMessage;
|
|
68
|
+
/** The leader's explanation for the agent set, when it gave one. */
|
|
69
|
+
selectionReason?: string;
|
|
70
|
+
}
|
|
71
|
+
export interface DeliverableSummary {
|
|
72
|
+
/** Path relative to the run work directory. */
|
|
73
|
+
path: string;
|
|
74
|
+
status: "created" | "modified";
|
|
75
|
+
size: number;
|
|
76
|
+
modifiedAt: string;
|
|
77
|
+
}
|
|
78
|
+
export interface OrchestratorResult {
|
|
79
|
+
name: string;
|
|
80
|
+
success: boolean;
|
|
81
|
+
totalDuration: number;
|
|
82
|
+
agentResults: import("./agent").AgentResult[];
|
|
83
|
+
startTime: string;
|
|
84
|
+
endTime: string;
|
|
85
|
+
/**
|
|
86
|
+
* Set when the run was stopped via its AbortSignal. Cancellation is a third
|
|
87
|
+
* outcome, not a flavour of failure: the team stopped because it was told to.
|
|
88
|
+
* It still reports `success: false` — a run that never finished must not exit
|
|
89
|
+
* 0 — but the console says "cancelled" rather than "failed", and the CLI can
|
|
90
|
+
* exit with the conventional 130.
|
|
91
|
+
*/
|
|
92
|
+
cancelled?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Set when the turn ended in words instead of a pipeline — the leader answered
|
|
95
|
+
* or asked a question, so no agent ran. Without it, "the team worked and
|
|
96
|
+
* succeeded" and "nobody worked" look identical: both are `success: true` with
|
|
97
|
+
* an empty `agentResults`.
|
|
98
|
+
*/
|
|
99
|
+
reply?: LeaderMessage;
|
|
100
|
+
/**
|
|
101
|
+
* The leader's explanation for the agent set it selected, when it gave one.
|
|
102
|
+
*
|
|
103
|
+
* This is orchestration metadata, not agent state: it answers "why did this
|
|
104
|
+
* turn run these agents?" without asking the leader again. Absent for a
|
|
105
|
+
* resumed run, a leader-less run, and any leader that omitted the field.
|
|
106
|
+
*/
|
|
107
|
+
selectionReason?: string;
|
|
108
|
+
/**
|
|
109
|
+
* Sum of the per-agent costs that were actually reported, in USD.
|
|
110
|
+
*
|
|
111
|
+
* Present only when at least one agent reported a cost — "no data" is not the
|
|
112
|
+
* same as "free", so a run in which nobody priced itself must leave this
|
|
113
|
+
* `undefined` rather than reporting `0`.
|
|
114
|
+
*/
|
|
115
|
+
totalCostUsd?: number;
|
|
116
|
+
/**
|
|
117
|
+
* The requirement this turn was run for, when the caller supplied one.
|
|
118
|
+
*
|
|
119
|
+
* Carried on the result because the completion event *is* the report a resume
|
|
120
|
+
* driver reads back: without it, a resumed run has no way to recover the
|
|
121
|
+
* requirement it is continuing.
|
|
122
|
+
*/
|
|
123
|
+
requirement?: string;
|
|
124
|
+
/** Files created or modified by this run, when the caller collected them. */
|
|
125
|
+
deliverables?: DeliverableSummary[];
|
|
126
|
+
}
|