@hydraharness/harness-subagent-fork-in-process 0.1.1-rc.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/LICENSE +21 -0
- package/README.md +59 -0
- package/lib/index.js +59 -0
- package/lib/invariant.js +23 -0
- package/lib/types/index.d.ts +20 -0
- package/lib/types/invariant.d.ts +16 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# @hydraharness/harness-subagent-fork-in-process
|
|
2
|
+
|
|
3
|
+
The fork provider creates an in-process child seeded with the parent's completed conversation turns. It shares all run mechanics with spawn; the session seed is the only behavioral difference.
|
|
4
|
+
|
|
5
|
+
## Seed boundary
|
|
6
|
+
|
|
7
|
+
The parent's current tool-calling turn is still open when a subagent starts: its log contains the assistant tool call but not the matching tool result or `turn/end`. Copying that raw log would give the child an invalid, unbalanced session.
|
|
8
|
+
|
|
9
|
+
Fork therefore computes the contiguous prefix ending at the last `turn/end`. The child sees all completed parent turns and none of the in-flight turn. If the parent has not completed a turn yet, the seed is empty and the child behaves like a fresh spawn.
|
|
10
|
+
|
|
11
|
+
The seed transfers conversation history only. The child still receives a fresh flat registration scope; it does not inherit the parent's tool restrictions or authority.
|
|
12
|
+
|
|
13
|
+
## Start and capabilities
|
|
14
|
+
|
|
15
|
+
`start(request)` passes the completed-turn seed to [`startInProcessRun`](../subagent-in-process-driver/README.md) and awaits child publication. The shared driver owns cancellation, depth, customization, result reading, and disposal.
|
|
16
|
+
|
|
17
|
+
Fork advertises `{ outputSchema: true, depthLimit: true, toolFilter: true, persona: true }`, identical to spawn.
|
|
18
|
+
|
|
19
|
+
## Config
|
|
20
|
+
|
|
21
|
+
| Key | Meaning |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `providerName` | Registry name on `ctx.subagents` (default `fork`). |
|
|
24
|
+
See [`@hydraharness/harness-subagent-spawn-in-process`](../subagent-spawn-in-process/README.md) for the run lifecycle, model inheritance, and depth tracking — all shared.
|
|
25
|
+
|
|
26
|
+
## Model Experience
|
|
27
|
+
|
|
28
|
+
### Child-agent history and envelope
|
|
29
|
+
|
|
30
|
+
#### What the model sees
|
|
31
|
+
|
|
32
|
+
The child receives the parent's balanced completed-turn surface prefix, then the new task content verbatim. A configured persona shadows prompt text in the child's fresh scope; a tool restriction filters its global wire schemas, executable lookup, and Code Mode SDK bindings but not standalone guidance. The parent's tool view and authority are not inherited. An optional structured-output request adds its child-only contract. The parent's current in-flight turn is excluded.
|
|
33
|
+
|
|
34
|
+
#### Token effect
|
|
35
|
+
|
|
36
|
+
Forking duplicates retained completed history into separate child requests; the child then accumulates its own tokens independently. Persona changes repeated prompt cost, filtering changes schema or generated SDK cost, and a first-turn fork has no inherited history.
|
|
37
|
+
|
|
38
|
+
#### KV Cache effect
|
|
39
|
+
|
|
40
|
+
The child may reuse the inherited byte-identical prefix under the same provider and model. Persona, tool-filter, generated-SDK, or route changes may invalidate reuse before inherited history; later child history is append-only. Shipped compositions therefore bind this provider to `backgroundMode: one-shot`, because a continuable child additionally carries the child-scoped `report` tool and its prompt section — deltas that precede the inherited history and so invalidate all of it ([the fork-one-shot Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md)).
|
|
41
|
+
|
|
42
|
+
### Parent tool result, indirectly
|
|
43
|
+
|
|
44
|
+
#### What the model sees
|
|
45
|
+
|
|
46
|
+
The parent receives only the child's own final output through `@hydraharness/harness-tool-subagent`, not the inherited prefix or intermediate work.
|
|
47
|
+
|
|
48
|
+
#### Token effect
|
|
49
|
+
|
|
50
|
+
Parent input grows by one data-dependent final result retained until compaction.
|
|
51
|
+
|
|
52
|
+
#### KV Cache effect
|
|
53
|
+
|
|
54
|
+
Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
|
|
55
|
+
|
|
56
|
+
## Known Limitations and Deferred Work
|
|
57
|
+
|
|
58
|
+
- **The seed is a one-time snapshot** — the child sees the parent's completed turns as of the fork and nothing the parent logs afterwards; there is no live context sharing.
|
|
59
|
+
- **No shipped composition creates a continuable fork child** — `prepareContinuable` remains implemented and the seam accepts it, but every shipped `cordis.yml` sets `backgroundMode: one-shot` on the fork delegation tool, so the provider's continuable path has no production caller. Reopening it requires the child's system prompt and tool schemas to match the parent's byte for byte, which the [`report` return channel](../tool-subagent-report/README.md) currently prevents. Rationale and the reintroduction condition: [the fork-one-shot Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md).
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import z from "@hydraharness/schemastery";
|
|
2
|
+
import { startInProcessRun } from "@hydraharness/harness-subagent-in-process-driver";
|
|
3
|
+
//#region lib/types/index.js
|
|
4
|
+
/**
|
|
5
|
+
* The in-process FORK subagent backend: registers a {@link SubagentProvider} on
|
|
6
|
+
* `ctx.subagents` that runs each child as a child {@link Agent} SEEDED with a prefix of the
|
|
7
|
+
* parent's session log — so the child inherits the parent's conversation context instead of
|
|
8
|
+
* starting fresh. The seed ends at the last `turn/end`: the current tool-call turn is
|
|
9
|
+
* unbalanced and cannot be replayed as a valid child session.
|
|
10
|
+
* @module @hydraharness/harness-subagent-fork-in-process
|
|
11
|
+
*/
|
|
12
|
+
const name = "subagent-fork-in-process";
|
|
13
|
+
const inject = ["subagents"];
|
|
14
|
+
const Config = z.object({ providerName: z.string().default("fork") });
|
|
15
|
+
/**
|
|
16
|
+
* The balanced completed-turn prefix of `parent`'s log: every event up to and including the
|
|
17
|
+
* last `turn/end`. The in-flight turn is excluded; before any completed turn the child starts
|
|
18
|
+
* fresh. Because live sequence numbers equal array indexes, the result remains a valid seed
|
|
19
|
+
* beginning at sequence zero.
|
|
20
|
+
* @param parent - the agent whose session log to slice.
|
|
21
|
+
* @returns the seed events, contiguous from seq 0; empty when no turn has completed.
|
|
22
|
+
*/
|
|
23
|
+
function completedTurnPrefix(parent) {
|
|
24
|
+
const events = parent.session.events;
|
|
25
|
+
const lastEnd = events.findLast((e) => e.type === "turn/end");
|
|
26
|
+
if (lastEnd === void 0) return [];
|
|
27
|
+
return events.slice(0, lastEnd.seq + 1);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The fork provider. Supports `depthLimit` and `outputSchema` (via the shared
|
|
31
|
+
* in-process structured runtime), plus `toolFilter`/`persona` (scoped
|
|
32
|
+
* restrict() and a scoped shadowing persona section).
|
|
33
|
+
*/
|
|
34
|
+
var ForkInProcessProvider = class {
|
|
35
|
+
name;
|
|
36
|
+
capabilities = {
|
|
37
|
+
outputSchema: true,
|
|
38
|
+
depthLimit: true,
|
|
39
|
+
toolFilter: true,
|
|
40
|
+
persona: true
|
|
41
|
+
};
|
|
42
|
+
inheritsParentContext = true;
|
|
43
|
+
constructor(name) {
|
|
44
|
+
this.name = name;
|
|
45
|
+
}
|
|
46
|
+
start(request) {
|
|
47
|
+
const seed = completedTurnPrefix(request.parent);
|
|
48
|
+
return startInProcessRun(request, { ...seed.length > 0 ? { seed } : {} });
|
|
49
|
+
}
|
|
50
|
+
prepareContinuable(request) {
|
|
51
|
+
const seed = completedTurnPrefix(request.parent);
|
|
52
|
+
return Promise.resolve(seed.length > 0 ? { seed } : {});
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
function apply(ctx, config) {
|
|
56
|
+
ctx.subagents.registerProvider(new ForkInProcessProvider(config.providerName));
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { Config, apply, inject, name };
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/**
|
|
3
|
+
* Package-owned invariant companion for `@hydraharness/harness-subagent-fork-in-process`.
|
|
4
|
+
* @module @hydraharness/harness-subagent-fork-in-process/invariant
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_NAME = "@hydraharness/harness-subagent-fork-in-process";
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
const name = "subagent-fork-in-process-invariant";
|
|
9
|
+
/** Service required before the companion can reserve package ownership. */
|
|
10
|
+
const inject = ["invariants"];
|
|
11
|
+
/**
|
|
12
|
+
* No runtime invariant: this package exposes no independent event sequence or mutable data relation
|
|
13
|
+
* beyond contracts enforced at its owning seam.
|
|
14
|
+
*/
|
|
15
|
+
const install = () => {};
|
|
16
|
+
/**
|
|
17
|
+
* Register this package's invariant companion.
|
|
18
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
19
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
20
|
+
*/
|
|
21
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
22
|
+
//#endregion
|
|
23
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The in-process FORK subagent backend: registers a {@link SubagentProvider} on
|
|
3
|
+
* `ctx.subagents` that runs each child as a child {@link Agent} SEEDED with a prefix of the
|
|
4
|
+
* parent's session log — so the child inherits the parent's conversation context instead of
|
|
5
|
+
* starting fresh. The seed ends at the last `turn/end`: the current tool-call turn is
|
|
6
|
+
* unbalanced and cannot be replayed as a valid child session.
|
|
7
|
+
* @module @hydraharness/harness-subagent-fork-in-process
|
|
8
|
+
*/
|
|
9
|
+
import type { Context } from '@hydraharness/cordis';
|
|
10
|
+
import z from '@hydraharness/schemastery';
|
|
11
|
+
export declare const name = "subagent-fork-in-process";
|
|
12
|
+
export declare const inject: string[];
|
|
13
|
+
/** Config: the registry name to register the provider under. */
|
|
14
|
+
export interface Config {
|
|
15
|
+
/** Provider name on `ctx.subagents` (default `fork`). */
|
|
16
|
+
providerName: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const Config: z<Config>;
|
|
19
|
+
export declare function apply(ctx: Context, config: Config): void;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@hydraharness/harness-subagent-fork-in-process`.
|
|
3
|
+
* @module @hydraharness/harness-subagent-fork-in-process/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@hydraharness/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "subagent-fork-in-process-invariant";
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register this package's invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hydraharness/harness-subagent-fork-in-process",
|
|
3
|
+
"description": "In-process fork subagent backend: runs a child agent seeded with a prefix of the parent's log",
|
|
4
|
+
"hydra": {
|
|
5
|
+
"plugin": {
|
|
6
|
+
"application": "Start a child agent with a copy of the parent conversation up to the fork point."
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"version": "0.1.1-rc.6",
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/MaiHongPhong1902/Hydra-Harness.git",
|
|
16
|
+
"directory": "packages/subagent/subagent-fork-in-process"
|
|
17
|
+
},
|
|
18
|
+
"type": "module",
|
|
19
|
+
"main": "lib/index.js",
|
|
20
|
+
"types": "lib/types/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./lib/types/index.d.ts",
|
|
24
|
+
"default": "./lib/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./invariant": {
|
|
27
|
+
"types": "./lib/types/invariant.d.ts",
|
|
28
|
+
"default": "./lib/invariant.js"
|
|
29
|
+
},
|
|
30
|
+
"./src/*": "./src/*",
|
|
31
|
+
"./package.json": "./package.json"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"lib/index.js",
|
|
35
|
+
"lib/invariant.js",
|
|
36
|
+
"lib/types/**/*.d.ts"
|
|
37
|
+
],
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@hydraharness/harness-agent": "^0.1.1-rc.6",
|
|
41
|
+
"@hydraharness/harness-session": "^0.1.1-rc.6",
|
|
42
|
+
"@hydraharness/harness-subagent-in-process-driver": "^0.1.1-rc.6",
|
|
43
|
+
"@hydraharness/harness-subagent": "^0.1.1-rc.6",
|
|
44
|
+
"@hydraharness/harness-invariants": "^0.1.1-rc.6",
|
|
45
|
+
"@hydraharness/cordis": "^4.0.2"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@hydraharness/schemastery": "^3.18.2"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@hydraharness/cordis-plugin-loader": "^1.0.3",
|
|
52
|
+
"@hydraharness/harness-agent": "^0.1.1-rc.6",
|
|
53
|
+
"@hydraharness/harness-agent-loop": "^0.1.1-rc.6",
|
|
54
|
+
"@hydraharness/harness-agent-loop-testkit": "^0.1.1-rc.6",
|
|
55
|
+
"@hydraharness/harness-invariants": "^0.1.1-rc.6",
|
|
56
|
+
"@hydraharness/harness-llm": "^0.1.1-rc.6",
|
|
57
|
+
"@hydraharness/harness-session": "^0.1.1-rc.6",
|
|
58
|
+
"@hydraharness/harness-subagent-in-process-driver": "^0.1.1-rc.6",
|
|
59
|
+
"@hydraharness/harness-subagent-spawn-in-process": "^0.1.1-rc.6",
|
|
60
|
+
"@hydraharness/cordis": "^4.0.2",
|
|
61
|
+
"@hydraharness/harness-subagent": "^0.1.1-rc.6"
|
|
62
|
+
}
|
|
63
|
+
}
|