@intentius/chant-lexicon-fountain 0.105.1 → 0.106.3
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/acp/serve.d.ts.map +1 -1
- package/dist/acp/server.d.ts +9 -0
- package/dist/acp/server.d.ts.map +1 -1
- package/dist/acp/turn.d.ts +2 -0
- package/dist/acp/turn.d.ts.map +1 -1
- package/dist/integrity.json +3 -3
- package/dist/manifest.json +1 -1
- package/dist/op/activities/fountain-prompt.d.ts +5 -4
- package/dist/op/activities/fountain-prompt.d.ts.map +1 -1
- package/dist/op/activities/fountain-run.d.ts +27 -17
- package/dist/op/activities/fountain-run.d.ts.map +1 -1
- package/dist/op/run-prompt.d.ts +52 -1
- package/dist/op/run-prompt.d.ts.map +1 -1
- package/dist/op/runtime.d.ts +24 -4
- package/dist/op/runtime.d.ts.map +1 -1
- package/dist/skills/chant-fountain-locked-sandboxes.md +1 -1
- package/package.json +2 -2
- package/src/acp/acp.test.ts +67 -1
- package/src/acp/serve.ts +8 -0
- package/src/acp/server.ts +11 -0
- package/src/acp/turn.ts +27 -2
- package/src/op/activities/fountain-prompt.ts +5 -4
- package/src/op/activities/fountain-run.test.ts +82 -1
- package/src/op/activities/fountain-run.ts +40 -27
- package/src/op/run-prompt.ts +103 -1
- package/src/op/runtime.test.ts +361 -2
- package/src/op/runtime.ts +125 -12
- package/src/skills/chant-fountain-locked-sandboxes.md +1 -1
package/dist/acp/serve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/acp/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,wFAAwF;AACxF,wBAAsB,iBAAiB,CAAC,IAAI,GAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/acp/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,wFAAwF;AACxF,wBAAsB,iBAAiB,CAAC,IAAI,GAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCjH"}
|
package/dist/acp/server.d.ts
CHANGED
|
@@ -42,6 +42,14 @@ export interface AcpServerOptions {
|
|
|
42
42
|
createHost?: (cwd: string) => ChantHost;
|
|
43
43
|
/** Mints permission request ids. Injected so a test can pin them. */
|
|
44
44
|
newRequestId?: () => string;
|
|
45
|
+
/**
|
|
46
|
+
* The id every Op run in this process is named by (#3539). On fountain it
|
|
47
|
+
* is the conversation id the sandbox's environment carries
|
|
48
|
+
* (`FOUNTAIN_CONVERSATION_ID`), so the run record the sandbox writes and
|
|
49
|
+
* the run `chant run status --on fountain` reports have the same id.
|
|
50
|
+
* Omitted, the local runtime mints one per run.
|
|
51
|
+
*/
|
|
52
|
+
runId?: string;
|
|
45
53
|
}
|
|
46
54
|
export declare class AcpServer implements JsonRpcHandler {
|
|
47
55
|
private peer;
|
|
@@ -50,6 +58,7 @@ export declare class AcpServer implements JsonRpcHandler {
|
|
|
50
58
|
private readonly version;
|
|
51
59
|
private readonly createHost;
|
|
52
60
|
private readonly newRequestId;
|
|
61
|
+
private readonly runId;
|
|
53
62
|
/** Serializes turns — see the module doc. */
|
|
54
63
|
private queue;
|
|
55
64
|
constructor(opts?: AcpServerOptions);
|
package/dist/acp/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/acp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EAEL,WAAW,EACX,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,WAAW,CAAC;AAoBnB,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGvE,mFAAmF;AACnF,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wFAAwF;IACxF,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,SAAS,CAAC;IACxC,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/acp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EAEL,WAAW,EACX,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,WAAW,CAAC;AAoBnB,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGvE,mFAAmF;AACnF,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wFAAwF;IACxF,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,SAAS,CAAC;IACxC,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAgBD,qBAAa,SAAU,YAAW,cAAc;IAC9C,OAAO,CAAC,IAAI,CAA0B;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IACvD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IACxD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAC3C,6CAA6C;IAC7C,OAAO,CAAC,KAAK,CAAuC;IAEpD,YAAY,IAAI,GAAE,gBAAqB,EAMtC;IAED,4CAA4C;IAC5C,OAAO,CAAC,SAAS,EAAE,aAAa,GAAG,WAAW,CAG7C;IAEK,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAW/D;IAED,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAQ5C;IAED,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,UAAU;IAuBlB,OAAO,CAAC,UAAU;YAYJ,MAAM;IAcpB;;;;;;OAMG;YACW,MAAM;YAuCN,cAAc;IAkC5B,8DAA8D;IAC9D,OAAO,CAAC,OAAO;CA0DhB"}
|
package/dist/acp/turn.d.ts
CHANGED
|
@@ -59,6 +59,8 @@ export interface TurnOptions {
|
|
|
59
59
|
durableRequests: boolean;
|
|
60
60
|
/** Mints the id a resume prompt names. Injected so a test can pin it. */
|
|
61
61
|
newRequestId: () => string;
|
|
62
|
+
/** The id an Op run is named by, when the host names runs (#3539: fountain's conversation id). */
|
|
63
|
+
runId?: string;
|
|
62
64
|
}
|
|
63
65
|
/**
|
|
64
66
|
* Run one prompt.
|
package/dist/acp/turn.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../../src/acp/turn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG/E,kDAAkD;AAClD,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7E,cAAc,CACZ,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,cAAc,EACtB,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAC9D,IAAI,CAAC;IACR,gFAAgF;IAChF,iBAAiB,CACf,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,gBAAgB,EAAE,EAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED,0FAA0F;AAC1F,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,UAAU,CAAC;IACvB,mEAAmE;IACnE,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC;AAED,iFAAiF;AACjF,eAAO,MAAM,YAAY,UAAU,CAAC;AACpC,eAAO,MAAM,aAAa,WAAW,CAAC;AA8BtC,iCAAiC;AACjC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;IACtB,2EAA2E;IAC3E,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,yEAAyE;IACzE,YAAY,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../../src/acp/turn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG/E,kDAAkD;AAClD,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7E,cAAc,CACZ,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,cAAc,EACtB,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAC9D,IAAI,CAAC;IACR,gFAAgF;IAChF,iBAAiB,CACf,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,gBAAgB,EAAE,EAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED,0FAA0F;AAC1F,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,UAAU,CAAC;IACvB,mEAAmE;IACnE,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC;AAED,iFAAiF;AACjF,eAAO,MAAM,YAAY,UAAU,CAAC;AACpC,eAAO,MAAM,aAAa,WAAW,CAAC;AA8BtC,iCAAiC;AACjC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;IACtB,2EAA2E;IAC3E,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,yEAAyE;IACzE,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,kGAAkG;IAClG,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAmCrE"}
|
package/dist/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "d991df566d8002caaa016de270498899957eae346f481467997be3bd0e339def",
|
|
5
5
|
"meta.json": "3301437a2a56eaf1a5cc8f6eabb18a40767f916e09701b2d9bf20aba4066738c",
|
|
6
6
|
"types/index.d.ts": "cf6b634fe0a8e9e96f1d9d07e3df53838def2683dc93dbe3c7fd971c6d3908ae",
|
|
7
7
|
"rules/ftn001-no-secret-literals.ts": "a417b194cd7039911cca9a0f14c49b042dfa6b1ee48517f7c2e22b16590a8599",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"skills/chant-fountain.md": "906a312756a02c88de634915f63ab4dfe1b1078ff4d8cfb4b6dc97eec14bc237",
|
|
22
22
|
"skills/chant-fountain-secrets.md": "40aa847d62547581bebdde630b54796c4e1cbf498869392e0d396d96a75c0ab6",
|
|
23
23
|
"skills/chant-fountain-ops.md": "4e72f0a0c7477a9e98f85ea45e49ba69e8a699f9c13ba0f0cf1cb20a88151373",
|
|
24
|
-
"skills/chant-fountain-locked-sandboxes.md": "
|
|
24
|
+
"skills/chant-fountain-locked-sandboxes.md": "7404ece96f2a3bc9105942fd3b6db156a3537db7e34c8cf2faa9ba87f5512567"
|
|
25
25
|
},
|
|
26
|
-
"composite": "
|
|
26
|
+
"composite": "6f4edb83df0d0f55abea6e8fbed09896f4a6a94a73e6f6a81aa21ccb093a916e"
|
|
27
27
|
}
|
package/dist/manifest.json
CHANGED
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
* What fountain v0.21.0 can and cannot do here, which decides the arguments:
|
|
14
14
|
*
|
|
15
15
|
* - A conversation that is `terminated` takes no more turns: the prompts route
|
|
16
|
-
* answers 410. `fountainRun` terminates an ephemeral agent's conversation
|
|
17
|
-
* its deadline by default, so a caller that wants a
|
|
18
|
-
* one with `terminate: "never"` (a persistent
|
|
19
|
-
* conversation itself, or with this op's
|
|
16
|
+
* answers 410. `fountainRun` terminates an ephemeral agent's conversation
|
|
17
|
+
* once its turn ends (or at its deadline) by default, so a caller that wants a
|
|
18
|
+
* later turn runs the first one with `terminate: "never"` (a persistent
|
|
19
|
+
* agent's default) and ends the conversation itself, or with this op's
|
|
20
|
+
* `terminate`, after the last turn.
|
|
20
21
|
* - A turn has no tool allowlist of its own. The prompts route takes only the
|
|
21
22
|
* prompt, images and `client_request_id`; the tools a conversation may use are
|
|
22
23
|
* its agent's `permission_policy`, narrowed once at launch, and nothing on the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fountain-prompt.d.ts","sourceRoot":"","sources":["../../../src/op/activities/fountain-prompt.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fountain-prompt.d.ts","sourceRoot":"","sources":["../../../src/op/activities/fountain-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAKtD,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,YAAY,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4FAA4F;IAC5F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,kCAAkC;IAClC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,eAAe,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,qBAAqB,EAAE,OAAO,CAAC;IAC/B,sHAAsH;IACtH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,UAAU,EAAE,OAAO,CAAC;CACrB;AAuCD,wBAAsB,cAAc,CAClC,IAAI,EAAE,kBAAkB,EACxB,MAAM,CAAC,EAAE,WAAW,EACpB,IAAI,CAAC,EAAE,YAAY,EACnB,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,oBAAoB,CAAC,CA2D/B"}
|
|
@@ -7,12 +7,18 @@
|
|
|
7
7
|
* imperative half: resolve the agent by name, POST the conversation, and
|
|
8
8
|
* poll until the turn is done.
|
|
9
9
|
*
|
|
10
|
-
* What "done" means depends on the agent's `sandbox_mode` (#2718).
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
10
|
+
* What "done" means depends on the agent's `sandbox_mode` (#2718). Any
|
|
11
|
+
* conversation is done at `completed | failed | timed_out | terminated`,
|
|
12
|
+
* but a running server's conversation reaches none of those on its own: when
|
|
13
|
+
* a turn ends, the conversation settles on `idle`. An `ephemeral`
|
|
14
|
+
* conversation is done once it is `idle` and its latest turn (`GET .../turns`)
|
|
15
|
+
* has ended (`completed | failed | interrupted`), and the result is that
|
|
16
|
+
* turn's outcome (#3386). Before #3386 this path waited for the four statuses
|
|
17
|
+
* only, so every ephemeral run waited out `timeoutMs` and was terminated. An
|
|
18
|
+
* ephemeral machine is its own, so by default it is terminated once the wait
|
|
19
|
+
* ends, cleanly or not (`terminate: "always"`); pass `terminate: "never"` to
|
|
20
|
+
* keep the conversation up for a later turn through `fountainPrompt`
|
|
21
|
+
* (#3356). A `persistent` agent's conversation
|
|
16
22
|
* (`Steward`, and `Box` from #2705) shares one machine across every
|
|
17
23
|
* conversation on it, and a turn ending there does not tear the sandbox
|
|
18
24
|
* down: the conversation settles on `idle`, not on any of the four
|
|
@@ -43,11 +49,12 @@
|
|
|
43
49
|
*/
|
|
44
50
|
import { type FountainHttp, type FountainConnectionDeps } from "./fountain-apply.js";
|
|
45
51
|
/**
|
|
46
|
-
* Conversation statuses that end
|
|
47
|
-
* and `timed_out` are not values fountain's `Conversation.status`
|
|
48
|
-
* today (its enum is `pending | running | idle | failed | terminated`)
|
|
49
|
-
* they are kept so a server that starts reporting them is handled without
|
|
50
|
-
*
|
|
52
|
+
* Conversation statuses that end any agent's run without reading its turns.
|
|
53
|
+
* `completed` and `timed_out` are not values fountain's `Conversation.status`
|
|
54
|
+
* takes today (its enum is `pending | running | idle | failed | terminated`);
|
|
55
|
+
* they are kept so a server that starts reporting them is handled without a
|
|
56
|
+
* further change here. An ephemeral conversation also ends on `idle` once its
|
|
57
|
+
* latest turn has ended (#3386).
|
|
51
58
|
*/
|
|
52
59
|
export declare const TERMINAL_STATUSES: Set<string>;
|
|
53
60
|
/**
|
|
@@ -105,10 +112,12 @@ export interface FountainRunArgs {
|
|
|
105
112
|
pollMs?: number;
|
|
106
113
|
/**
|
|
107
114
|
* When to terminate the conversation's machine (#2718). Default follows
|
|
108
|
-
* the agent's `sandbox_mode`: `
|
|
109
|
-
*
|
|
115
|
+
* the agent's `sandbox_mode`: `always` for `ephemeral` (the machine is the
|
|
116
|
+
* run's own, so it goes once the turn ends or the deadline fires, #3386),
|
|
117
|
+
* `never` for `persistent` (its machine is a home meant to outlive the
|
|
110
118
|
* conversation, so a run that hits its deadline leaves it be unless this
|
|
111
|
-
* says otherwise.
|
|
119
|
+
* says otherwise). Pass `never` on an ephemeral run to send it a later turn
|
|
120
|
+
* with `fountainPrompt`.
|
|
112
121
|
*/
|
|
113
122
|
terminate?: TerminatePolicy;
|
|
114
123
|
/** Injectable clock/sleep for tests. */
|
|
@@ -117,9 +126,10 @@ export interface FountainRunArgs {
|
|
|
117
126
|
export interface FountainRunResult {
|
|
118
127
|
conversationId: string;
|
|
119
128
|
/**
|
|
120
|
-
* The run's outcome. For a
|
|
121
|
-
* turn
|
|
122
|
-
*
|
|
129
|
+
* The run's outcome. For a conversation that settled on `idle` after its
|
|
130
|
+
* turn (persistent, or ephemeral since #3386), this is the turn's own
|
|
131
|
+
* status (`completed | failed | interrupted`); otherwise it is the
|
|
132
|
+
* conversation's status when the wait ended (`terminated` on a
|
|
123
133
|
* deadline). For a persistent agent launched with no prompt (#2781), it is
|
|
124
134
|
* the sandbox's outcome: `provisioned` or `failed`.
|
|
125
135
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fountain-run.d.ts","sourceRoot":"","sources":["../../../src/op/activities/fountain-run.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fountain-run.d.ts","sourceRoot":"","sources":["../../../src/op/activities/fountain-run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC5B,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,aAA8D,CAAC;AAE7F;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,aAA0C,CAAC;AAKhF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,aAAa,GAAG,QAAQ,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,wCAAwC;IACxC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;;OAOG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,UAAU,EAAE,OAAO,CAAC;IACpB,wEAAwE;IACxE,oBAAoB,EAAE,OAAO,CAAC;IAC9B,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yHAAyH;IACzH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAaD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qEAAqE;AACrE,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAe5F;AAED,qFAAqF;AACrF,wBAAsB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGvF;AAyCD,wBAAsB,WAAW,CAC/B,IAAI,EAAE,eAAe,EACrB,MAAM,CAAC,EAAE,WAAW,EACpB,IAAI,CAAC,EAAE,YAAY,EACnB,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,iBAAiB,CAAC,CAwH5B"}
|
package/dist/op/run-prompt.d.ts
CHANGED
|
@@ -9,6 +9,57 @@
|
|
|
9
9
|
* spelling of the same command. Hence one module, imported by both, with no
|
|
10
10
|
* dependencies of its own so neither drags the other in.
|
|
11
11
|
*/
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* The bare line one run of `op` is: what a steward's Schedule posts, and the
|
|
14
|
+
* prefix a turn is matched by. The runtime posts {@link hostedRunPrompt}.
|
|
15
|
+
*/
|
|
13
16
|
export declare function runPrompt(op: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* One argument as the posted command line spells it (#3539): bare when it is
|
|
19
|
+
* a plain word, otherwise in double quotes with `\` and `"` escaped, which
|
|
20
|
+
* is the quoting `tokenize` undoes. An approver named "Alex Smith" reaches the
|
|
21
|
+
* sandbox as one `--approver` value rather than as `Alex` and a stray `Smith`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function quoteArg(value: string): string;
|
|
24
|
+
/** What {@link hostedRunPrompt} puts on the line after `chant run <op>`. */
|
|
25
|
+
export interface HostedRunPromptOptions {
|
|
26
|
+
/** `--env`: refused by name unless it is one plain word. */
|
|
27
|
+
env?: string;
|
|
28
|
+
/** `--param name=value`, one flag per entry, in order (#3539). */
|
|
29
|
+
params?: Record<string, unknown>;
|
|
30
|
+
/**
|
|
31
|
+
* `--work <item>` and `--holder <name>` (#3555): the work item the run is
|
|
32
|
+
* for and who holds its lease. The sandbox's run takes the lease.
|
|
33
|
+
*/
|
|
34
|
+
work?: {
|
|
35
|
+
item?: string;
|
|
36
|
+
holder?: string;
|
|
37
|
+
};
|
|
38
|
+
/** Flags after `--on local`, as `[flag, value]`; each value is quoted as needed. */
|
|
39
|
+
flags?: Array<[string, string]>;
|
|
40
|
+
/** Words appended as they are, already spelled for the command line. */
|
|
41
|
+
extra?: string[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The prompt a hosted run is posted as: {@link runPrompt}, then `--env <env>`
|
|
45
|
+
* when the caller named one (#3232), then each `--param` (#3539), then
|
|
46
|
+
* `--work` and `--holder` (#3555), then `--on local` (#3225), then any
|
|
47
|
+
* further flags.
|
|
48
|
+
*
|
|
49
|
+
* `--env` carries the environment the caller asked for into the sandbox,
|
|
50
|
+
* where `chant acp` hands it to the run as `currentOpRun().env`. `--param`
|
|
51
|
+
* rides along so the sandbox runs the line the caller typed. `--on local`
|
|
52
|
+
* keeps a project's `run.on: "fountain"` from sending the posted command
|
|
53
|
+
* back to fountain: the sandbox runs the Op itself. `chant acp` already runs
|
|
54
|
+
* every `chant run <op>` on the local runtime; the flag makes the same true
|
|
55
|
+
* for any other agent that runs the line at a shell.
|
|
56
|
+
*
|
|
57
|
+
* A turn still matches {@link runPrompt} by prefix (`turnRunsOp`), and a
|
|
58
|
+
* steward's Schedule keeps the bare line. An `--env` value that is not one
|
|
59
|
+
* plain word is refused by name rather than posted, as is a `--work` or
|
|
60
|
+
* `--holder` value the sandbox's parser would not read as a value (empty, or
|
|
61
|
+
* starting with `-`); a `--param`, `--work`, `--holder` or flag value is
|
|
62
|
+
* quoted ({@link quoteArg}).
|
|
63
|
+
*/
|
|
64
|
+
export declare function hostedRunPrompt(op: string, opts?: HostedRunPromptOptions): string;
|
|
14
65
|
//# sourceMappingURL=run-prompt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-prompt.d.ts","sourceRoot":"","sources":["../../src/op/run-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,oFAAoF;
|
|
1
|
+
{"version":3,"file":"run-prompt.d.ts","sourceRoot":"","sources":["../../src/op/run-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE5C;AAeD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED,4EAA4E;AAC5E,MAAM,WAAW,sBAAsB;IACrC,4DAA4D;IAC5D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC;;;OAGG;IACH,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,oFAAoF;IACpF,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChC,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,sBAA2B,GAAG,MAAM,CA4BrF"}
|
package/dist/op/runtime.d.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* `chant run <op> --on fountain` hands the run to a fountain teammate instead
|
|
5
5
|
* of executing it here. This module is the client for that: it posts the
|
|
6
|
-
* command line `chant run <op
|
|
6
|
+
* command line `chant run <op> [--env <env>] [--param k=v ...] [--work <id>] [--holder <name>] --on local` ({@link hostedRunPrompt})
|
|
7
|
+
* as a prompt on the steward's thread, tails the
|
|
7
8
|
* conversation's SSE stream, and reports what comes back through the
|
|
8
9
|
* {@link OpRuntimeProvider} contract core defines in
|
|
9
10
|
* `packages/core/src/op/runtime.ts`.
|
|
@@ -62,8 +63,8 @@
|
|
|
62
63
|
import { type ChantConfig } from "@intentius/chant/config";
|
|
63
64
|
import type { OpRunRecord, OpRunState, OpRunStatus, OpRuntimeProvider, StepRecord } from "@intentius/chant/op";
|
|
64
65
|
import { type FountainHttp } from "./activities/fountain-apply.js";
|
|
65
|
-
import { runPrompt } from "./run-prompt.js";
|
|
66
|
-
export { runPrompt };
|
|
66
|
+
import { runPrompt, hostedRunPrompt, quoteArg } from "./run-prompt.js";
|
|
67
|
+
export { runPrompt, hostedRunPrompt, quoteArg };
|
|
67
68
|
/** One server-sent event, already framed. `data` is the raw payload text. */
|
|
68
69
|
export interface FountainSseEvent {
|
|
69
70
|
/** The event id, which becomes the next connection's `Last-Event-ID`. */
|
|
@@ -181,7 +182,7 @@ export declare function conversationIsTerminal(status?: string): boolean;
|
|
|
181
182
|
* turn — its status, its sandbox's, and how many turns it managed. Pure.
|
|
182
183
|
*/
|
|
183
184
|
export declare function conversationFailureReason(conversation: Conversation): string;
|
|
184
|
-
/** Does this turn's prompt name `op`? The prompt is `chant run <op>`,
|
|
185
|
+
/** Does this turn's prompt name `op`? The prompt is `chant run <op>`, alone or followed by flags. */
|
|
185
186
|
export declare function turnRunsOp(turn: Turn, op: string): boolean;
|
|
186
187
|
/**
|
|
187
188
|
* The run record a turn's final message carries.
|
|
@@ -207,6 +208,19 @@ export declare function runStateOfTurn(conversationStatus?: string, turnState?:
|
|
|
207
208
|
* processes, because nothing here is this client's to remember.
|
|
208
209
|
*/
|
|
209
210
|
export declare function createFountainOpRuntime(opts?: FountainOpRuntimeOptions): OpRuntimeProvider;
|
|
211
|
+
/**
|
|
212
|
+
* The `--env`, `--param`s, `--work` and `--holder` a posted prompt carries,
|
|
213
|
+
* read with the same quote-aware split `chant acp` uses. A prompt that does
|
|
214
|
+
* not split (an unterminated quote) carries none of them.
|
|
215
|
+
*/
|
|
216
|
+
export declare function flagsOfPrompt(prompt: string | undefined): {
|
|
217
|
+
env?: string;
|
|
218
|
+
params?: Record<string, string>;
|
|
219
|
+
work?: {
|
|
220
|
+
item?: string;
|
|
221
|
+
holder?: string;
|
|
222
|
+
};
|
|
223
|
+
};
|
|
210
224
|
interface TailOptions {
|
|
211
225
|
sse: FountainSse;
|
|
212
226
|
conversationId: string;
|
|
@@ -223,6 +237,12 @@ interface TailOptions {
|
|
|
223
237
|
http?: FountainHttp;
|
|
224
238
|
/** How much silence asks fountain about the conversation. Default 2s. */
|
|
225
239
|
pollIntervalMs?: number;
|
|
240
|
+
/**
|
|
241
|
+
* Turn ids that existed before this run's prompt was posted. The stream
|
|
242
|
+
* replays the whole log on a first connection, so events of these turns are
|
|
243
|
+
* skipped: an earlier turn's `done` must not settle this run (#3524).
|
|
244
|
+
*/
|
|
245
|
+
ignoreTurns?: ReadonlySet<string>;
|
|
226
246
|
}
|
|
227
247
|
/**
|
|
228
248
|
* Tail one conversation to the end of its turn.
|
package/dist/op/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/op/runtime.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/op/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,4 +31,4 @@ The environment's config is the enforcement boundary, so watch it: `chant lifecy
|
|
|
31
31
|
|
|
32
32
|
## Running conversations
|
|
33
33
|
|
|
34
|
-
Conversations are runs, not resources. Use the `fountainRun` activity: resolves the agent by name, starts (optionally with a prompt and an allowlisted vault), and waits for the turn to end. What "end" means, and what happens to the machine, follows the agent's `sandbox_mode`: an `ephemeral` agent's conversation is
|
|
34
|
+
Conversations are runs, not resources. Use the `fountainRun` activity: resolves the agent by name, starts (optionally with a prompt and an allowlisted vault), and waits for the turn to end. What "end" means, and what happens to the machine, follows the agent's `sandbox_mode`: an `ephemeral` agent's conversation is done once it settles on `idle` with its turn ended, and `fountainRun` returns that turn's outcome and terminates the machine (`terminate: "always"`, its default; pass `"never"` to keep it for a later turn); a `persistent` agent's (a `Steward` or `Box`) conversation settles on `idle` once its turn ends — machine still up for the next turn — so `fountainRun` reads the turn back and returns its outcome (`completed | failed | interrupted`) without terminating anything, by default. Pass `terminate: "on-deadline" | "always"` to opt a persistent agent's run back into ending the machine. To add a turn to a conversation that already exists, use `fountainPrompt` with the conversation's id: it sends the prompt on the same session and waits for that turn, interrupting it at `timeoutMs`. It cannot reach a terminated conversation (fountain answers 410), so run the earlier turn with `terminate: "never"`, and it cannot narrow tools for one turn: that is the agent's `permission_policy`, set at launch. Interrupts and permission answers on their own are fountain's own conversations API.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-fountain",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.106.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Fountain lexicon for chant — sandboxed agent environments, vaults, and agents as typed estate",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"bundle": "tsx src/package-cli.ts"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@intentius/chant": "^0.
|
|
53
|
+
"@intentius/chant": "^0.106.3",
|
|
54
54
|
"typescript": "^5.9.3",
|
|
55
55
|
"zod": "^4.3.6"
|
|
56
56
|
},
|
package/src/acp/acp.test.ts
CHANGED
|
@@ -8,8 +8,15 @@
|
|
|
8
8
|
* would pass without the protocol ever being spoken.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { describe, it, expect } from "vitest";
|
|
11
|
+
import { describe, it, expect, vi } from "vitest";
|
|
12
12
|
import { PassThrough } from "node:stream";
|
|
13
|
+
|
|
14
|
+
// The workspace's sealed gates (`identity.gates`), standing in for a project's declaration.
|
|
15
|
+
const sealedGates = new Set<string>();
|
|
16
|
+
vi.mock("@intentius/chant/op/gate", async (importOriginal) => {
|
|
17
|
+
const actual = await importOriginal<typeof import("@intentius/chant/op/gate")>();
|
|
18
|
+
return { ...actual, gateIsSealed: async (gate: string) => sealedGates.has(gate) };
|
|
19
|
+
});
|
|
13
20
|
import {
|
|
14
21
|
JsonRpcPeer,
|
|
15
22
|
memoryTransportPair,
|
|
@@ -126,6 +133,8 @@ interface StubHostOptions {
|
|
|
126
133
|
|
|
127
134
|
interface StubHost extends ChantHost {
|
|
128
135
|
started: string[];
|
|
136
|
+
/** The options each `startOp` was handed, in order. */
|
|
137
|
+
startOpts: OpRunStartOptions[];
|
|
129
138
|
verbsRun: string[];
|
|
130
139
|
resolvedGates: Array<{ op: string; gate: string; by: string }>;
|
|
131
140
|
firstStep: Promise<void>;
|
|
@@ -140,6 +149,7 @@ function stubHost(opts: StubHostOptions = {}): StubHost {
|
|
|
140
149
|
const host: StubHost = {
|
|
141
150
|
cwd: process.cwd(),
|
|
142
151
|
started: [],
|
|
152
|
+
startOpts: [],
|
|
143
153
|
verbsRun: [],
|
|
144
154
|
resolvedGates: [],
|
|
145
155
|
firstStep,
|
|
@@ -153,6 +163,7 @@ function stubHost(opts: StubHostOptions = {}): StubHost {
|
|
|
153
163
|
},
|
|
154
164
|
async startOp(op: OpConfig, start: OpRunStartOptions): Promise<OpRunHandle> {
|
|
155
165
|
host.started.push(op.name);
|
|
166
|
+
host.startOpts.push(start);
|
|
156
167
|
const runId = "run-1";
|
|
157
168
|
const settled = (async (): Promise<OpRunStatus> => {
|
|
158
169
|
const records = opts.records ?? [];
|
|
@@ -405,6 +416,39 @@ describe("chant acp", () => {
|
|
|
405
416
|
}
|
|
406
417
|
});
|
|
407
418
|
|
|
419
|
+
// #3539: on fountain the session names every run by the conversation id,
|
|
420
|
+
// and a prompt's --param and --work reach the run as `chant run` passes them.
|
|
421
|
+
it("names the run by the server's runId and passes --env, --param and --work through", async () => {
|
|
422
|
+
const host = stubHost({ records: okRecords });
|
|
423
|
+
const server = new AcpServer({ createHost: () => host, runId: "conv-42" });
|
|
424
|
+
const { client, sessionId } = await open(server);
|
|
425
|
+
|
|
426
|
+
await client.peer.request("session/prompt", {
|
|
427
|
+
sessionId,
|
|
428
|
+
prompt: promptOf('chant run demo-op --env prod --param tier=gold --param "note=two words" --work ISSUE-7 --on local'),
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
expect(host.startOpts).toHaveLength(1);
|
|
432
|
+
expect(host.startOpts[0]).toMatchObject({
|
|
433
|
+
env: "prod",
|
|
434
|
+
runId: "conv-42",
|
|
435
|
+
params: { tier: "gold", note: "two words" },
|
|
436
|
+
work: { item: "ISSUE-7" },
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it("leaves the run id to the runtime when the server names none", async () => {
|
|
441
|
+
const host = stubHost({ records: okRecords });
|
|
442
|
+
const server = new AcpServer({ createHost: () => host });
|
|
443
|
+
const { client, sessionId } = await open(server);
|
|
444
|
+
|
|
445
|
+
await client.peer.request("session/prompt", { sessionId, prompt: promptOf("chant run demo-op") });
|
|
446
|
+
|
|
447
|
+
expect(host.startOpts[0]).not.toHaveProperty("runId");
|
|
448
|
+
expect(host.startOpts[0]).not.toHaveProperty("params");
|
|
449
|
+
expect(host.startOpts[0]).not.toHaveProperty("work");
|
|
450
|
+
});
|
|
451
|
+
|
|
408
452
|
it("replies with the run record as the final chunk", async () => {
|
|
409
453
|
const record = {
|
|
410
454
|
version: 1 as const,
|
|
@@ -527,12 +571,34 @@ describe("chant acp", () => {
|
|
|
527
571
|
|
|
528
572
|
expect(result.stopReason).toBe("end_turn");
|
|
529
573
|
expect(text(client.updates)).toContain("chant approve demo-op deploy");
|
|
574
|
+
expect(text(client.updates)).not.toContain("--sign");
|
|
530
575
|
expect(client.permissionRequests).toEqual([]);
|
|
531
576
|
|
|
532
577
|
// A step the run never reached is settled rather than left spinning.
|
|
533
578
|
expect(toolUpdates(client.updates).length).toBe(toolCalls(client.updates).length);
|
|
534
579
|
});
|
|
535
580
|
|
|
581
|
+
it("names --sign in the approve hint when the gate is sealed (#3521)", async () => {
|
|
582
|
+
sealedGates.add("deploy");
|
|
583
|
+
try {
|
|
584
|
+
const host = stubHost({
|
|
585
|
+
records: [okRecords[0]],
|
|
586
|
+
status: {
|
|
587
|
+
state: "gated",
|
|
588
|
+
gate: { name: "deploy", since: "2026-09-06T00:00:01.000Z" },
|
|
589
|
+
} as Partial<OpRunStatus>,
|
|
590
|
+
});
|
|
591
|
+
const server = new AcpServer({ createHost: () => host });
|
|
592
|
+
const { client, sessionId } = await open(server);
|
|
593
|
+
|
|
594
|
+
await client.peer.request("session/prompt", { sessionId, prompt: promptOf("chant run demo-op") });
|
|
595
|
+
|
|
596
|
+
expect(text(client.updates)).toContain("chant approve demo-op deploy --sign");
|
|
597
|
+
} finally {
|
|
598
|
+
sealedGates.delete("deploy");
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
|
|
536
602
|
it("asks for permission and waits under --durable-requests, then completes on resume", async () => {
|
|
537
603
|
let gated = true;
|
|
538
604
|
const gatedHost = stubHost({
|
package/src/acp/serve.ts
CHANGED
|
@@ -33,9 +33,17 @@ export async function serveAcpOverStdio(opts: { durableRequests?: boolean; stewa
|
|
|
33
33
|
// this session is refused, as the gate's resolution is above.
|
|
34
34
|
if (opts.steward) setStewardTurn({ steward: opts.steward });
|
|
35
35
|
|
|
36
|
+
// chant#3539 — fountain gives the command it spawns the conversation's id
|
|
37
|
+
// in `FOUNTAIN_CONVERSATION_ID` (process env only, never on disk), and
|
|
38
|
+
// `chant run <op> --on fountain` names the run by that same id. Naming the
|
|
39
|
+
// sandbox's runs by it joins the two: the run record written here carries
|
|
40
|
+
// the id the caller's `chant run status` reports.
|
|
41
|
+
const conversationId = process.env.FOUNTAIN_CONVERSATION_ID?.trim();
|
|
42
|
+
|
|
36
43
|
const server = new AcpServer({
|
|
37
44
|
durableRequests: opts.durableRequests ?? false,
|
|
38
45
|
version: lexiconVersion(),
|
|
46
|
+
...(conversationId ? { runId: conversationId } : {}),
|
|
39
47
|
});
|
|
40
48
|
|
|
41
49
|
const transport = streamTransport(process.stdin, process.stdout);
|
package/src/acp/server.ts
CHANGED
|
@@ -70,6 +70,14 @@ export interface AcpServerOptions {
|
|
|
70
70
|
createHost?: (cwd: string) => ChantHost;
|
|
71
71
|
/** Mints permission request ids. Injected so a test can pin them. */
|
|
72
72
|
newRequestId?: () => string;
|
|
73
|
+
/**
|
|
74
|
+
* The id every Op run in this process is named by (#3539). On fountain it
|
|
75
|
+
* is the conversation id the sandbox's environment carries
|
|
76
|
+
* (`FOUNTAIN_CONVERSATION_ID`), so the run record the sandbox writes and
|
|
77
|
+
* the run `chant run status --on fountain` reports have the same id.
|
|
78
|
+
* Omitted, the local runtime mints one per run.
|
|
79
|
+
*/
|
|
80
|
+
runId?: string;
|
|
73
81
|
}
|
|
74
82
|
|
|
75
83
|
/** One open session: a working directory, the turn in flight, and any gate awaiting an answer. */
|
|
@@ -93,6 +101,7 @@ export class AcpServer implements JsonRpcHandler {
|
|
|
93
101
|
private readonly version: string;
|
|
94
102
|
private readonly createHost: (cwd: string) => ChantHost;
|
|
95
103
|
private readonly newRequestId: () => string;
|
|
104
|
+
private readonly runId: string | undefined;
|
|
96
105
|
/** Serializes turns — see the module doc. */
|
|
97
106
|
private queue: Promise<unknown> = Promise.resolve();
|
|
98
107
|
|
|
@@ -101,6 +110,7 @@ export class AcpServer implements JsonRpcHandler {
|
|
|
101
110
|
this.version = opts.version ?? "dev";
|
|
102
111
|
this.createHost = opts.createHost ?? createChantHost;
|
|
103
112
|
this.newRequestId = opts.newRequestId ?? (() => randomUUID());
|
|
113
|
+
this.runId = opts.runId !== undefined && opts.runId !== "" ? opts.runId : undefined;
|
|
104
114
|
}
|
|
105
115
|
|
|
106
116
|
/** Serve one connection until it closes. */
|
|
@@ -256,6 +266,7 @@ export class AcpServer implements JsonRpcHandler {
|
|
|
256
266
|
signal: controller.signal,
|
|
257
267
|
durableRequests: this.durableRequests,
|
|
258
268
|
newRequestId: this.newRequestId,
|
|
269
|
+
...(this.runId ? { runId: this.runId } : {}),
|
|
259
270
|
});
|
|
260
271
|
if (outcome.permission) {
|
|
261
272
|
session.permissions.set(outcome.permission.requestId, { ...outcome.permission });
|
package/src/acp/turn.ts
CHANGED
|
@@ -22,7 +22,7 @@ import type { OpConfig, StepDefinition } from "@intentius/chant/op/types";
|
|
|
22
22
|
import type { StepRecord } from "@intentius/chant/op/local-executor";
|
|
23
23
|
import type { OpRunStatus } from "@intentius/chant/op/runtime";
|
|
24
24
|
import type { PendingGateRecord } from "@intentius/chant/lifecycle/gate-ledger";
|
|
25
|
-
import { approveCommand } from "@intentius/chant/op/gate";
|
|
25
|
+
import { approveCommand, gateIsSealed } from "@intentius/chant/op/gate";
|
|
26
26
|
import { gateName } from "@intentius/chant/op/gate-name";
|
|
27
27
|
import type { ChantCommand } from "./command-line";
|
|
28
28
|
import type { ChantHost } from "./host";
|
|
@@ -106,6 +106,8 @@ export interface TurnOptions {
|
|
|
106
106
|
durableRequests: boolean;
|
|
107
107
|
/** Mints the id a resume prompt names. Injected so a test can pin it. */
|
|
108
108
|
newRequestId: () => string;
|
|
109
|
+
/** The id an Op run is named by, when the host names runs (#3539: fountain's conversation id). */
|
|
110
|
+
runId?: string;
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
/**
|
|
@@ -210,8 +212,19 @@ async function runOpTurn(
|
|
|
210
212
|
|
|
211
213
|
let status: OpRunStatus;
|
|
212
214
|
try {
|
|
215
|
+
// What `chant run` itself hands a runtime (#3539): the run's id, when
|
|
216
|
+
// the session names it, and the prompt's `--param` and `--work`, which a
|
|
217
|
+
// turn used to drop.
|
|
218
|
+
const params = paramsOf(command.args.param);
|
|
219
|
+
const work = {
|
|
220
|
+
...(command.args.work !== undefined ? { item: command.args.work } : {}),
|
|
221
|
+
...(command.args.holder !== undefined ? { holder: command.args.holder } : {}),
|
|
222
|
+
};
|
|
213
223
|
const handle = await host.startOp(config, {
|
|
214
224
|
...(command.args.env ? { env: command.args.env } : {}),
|
|
225
|
+
...(opts.runId ? { runId: opts.runId } : {}),
|
|
226
|
+
...(params ? { params } : {}),
|
|
227
|
+
...(Object.keys(work).length > 0 ? { work } : {}),
|
|
215
228
|
progress: settle,
|
|
216
229
|
signal,
|
|
217
230
|
});
|
|
@@ -252,6 +265,18 @@ async function runOpTurn(
|
|
|
252
265
|
return { stopReason: "end_turn" };
|
|
253
266
|
}
|
|
254
267
|
|
|
268
|
+
/** `--param name=value` flags as a record, the way `chant run` reads them. */
|
|
269
|
+
function paramsOf(entries: string[] | undefined): Record<string, string> | undefined {
|
|
270
|
+
if (!entries?.length) return undefined;
|
|
271
|
+
const out: Record<string, string> = {};
|
|
272
|
+
for (const entry of entries) {
|
|
273
|
+
const eq = entry.indexOf("=");
|
|
274
|
+
if (eq === -1) out[entry] = "";
|
|
275
|
+
else out[entry.slice(0, eq)] = entry.slice(eq + 1);
|
|
276
|
+
}
|
|
277
|
+
return out;
|
|
278
|
+
}
|
|
279
|
+
|
|
255
280
|
/**
|
|
256
281
|
* A gated run's reply.
|
|
257
282
|
*
|
|
@@ -277,7 +302,7 @@ async function gatedReply(
|
|
|
277
302
|
sink.message(
|
|
278
303
|
`Op "${command.op}" is waiting on gate "${gate.name}", pending since ${gate.since}` +
|
|
279
304
|
(pending?.expiresAt ? ` and expiring ${pending.expiresAt}` : "") +
|
|
280
|
-
`.\nApprove with: ${approveCommand(command.op, gate.name)}\n`,
|
|
305
|
+
`.\nApprove with: ${approveCommand(command.op, gate.name, undefined, undefined, await gateIsSealed(gate.name))}\n`,
|
|
281
306
|
);
|
|
282
307
|
sink.message(JSON.stringify(status.result?.record ?? status, null, 2) + "\n");
|
|
283
308
|
|
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
* What fountain v0.21.0 can and cannot do here, which decides the arguments:
|
|
14
14
|
*
|
|
15
15
|
* - A conversation that is `terminated` takes no more turns: the prompts route
|
|
16
|
-
* answers 410. `fountainRun` terminates an ephemeral agent's conversation
|
|
17
|
-
* its deadline by default, so a caller that wants a
|
|
18
|
-
* one with `terminate: "never"` (a persistent
|
|
19
|
-
* conversation itself, or with this op's
|
|
16
|
+
* answers 410. `fountainRun` terminates an ephemeral agent's conversation
|
|
17
|
+
* once its turn ends (or at its deadline) by default, so a caller that wants a
|
|
18
|
+
* later turn runs the first one with `terminate: "never"` (a persistent
|
|
19
|
+
* agent's default) and ends the conversation itself, or with this op's
|
|
20
|
+
* `terminate`, after the last turn.
|
|
20
21
|
* - A turn has no tool allowlist of its own. The prompts route takes only the
|
|
21
22
|
* prompt, images and `client_request_id`; the tools a conversation may use are
|
|
22
23
|
* its agent's `permission_policy`, narrowed once at launch, and nothing on the
|