@sublang/playbook 7.0.0 → 8.0.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/README.md +17 -4
- package/docs/cli.md +74 -29
- package/docs/configuration.md +209 -112
- package/docs/embedding.md +71 -25
- package/package.json +4 -3
- package/reference/sdlc/captain.playbook/captain.playbook.js +3 -3
- package/reference/sdlc/captain.playbook/captain.playbook.ts +3 -3
- package/reference/sdlc/code.md +1 -1
- package/reference/sdlc/code.playbook/bin/interactive-session.js +816 -0
- package/reference/sdlc/code.playbook/bin/launch-config.js +1078 -116
- package/reference/sdlc/code.playbook/bin/playbook.js +489 -34
- package/reference/sdlc/code.playbook/bin/run.js +283 -298
- package/reference/sdlc/code.playbook/bin/session-store.js +818 -26
- package/reference/sdlc/code.playbook/code.fsm.d.ts +5 -5
- package/reference/sdlc/code.playbook/code.fsm.introspect.js +2 -2
- package/reference/sdlc/code.playbook/code.fsm.introspect.ts +2 -2
- package/reference/sdlc/code.playbook/code.fsm.js +7 -11
- package/reference/sdlc/code.playbook/code.fsm.ts +9 -17
- package/reference/sdlc/code.playbook/code.gears.md +1 -1
- package/reference/sdlc/code.playbook/code.playbook.d.ts +2 -1
- package/reference/sdlc/code.playbook/code.playbook.js +12 -13
- package/reference/sdlc/code.playbook/code.playbook.ts +22 -15
- package/reference/sdlc/code.playbook/code.registry.d.ts +5 -13
- package/reference/sdlc/code.playbook/code.registry.js +3 -10
- package/reference/sdlc/code.playbook/code.registry.ts +7 -32
- package/reference/sdlc/code.playbook/playbook-captain.d.ts +39 -14
- package/reference/sdlc/code.playbook/playbook-captain.js +970 -289
- package/reference/sdlc/code.playbook/playbook-captain.ts +1403 -396
- package/reference/sdlc/code.playbook/playbook.config.template.yaml +41 -49
- package/reference/sdlc/decide.md +4 -4
- package/reference/sdlc/decide.playbook/decide.fsm.d.ts +9 -9
- package/reference/sdlc/decide.playbook/decide.fsm.js +21 -14
- package/reference/sdlc/decide.playbook/decide.fsm.ts +27 -23
- package/reference/sdlc/decide.playbook/decide.gears.md +3 -5
- package/reference/sdlc/decide.playbook/decide.playbook.d.ts +9 -13
- package/reference/sdlc/decide.playbook/decide.playbook.js +171 -134
- package/reference/sdlc/decide.playbook/decide.playbook.ts +238 -162
- package/reference/sdlc/decide.playbook/decide.registry.d.ts +5 -13
- package/reference/sdlc/decide.playbook/decide.registry.js +3 -9
- package/reference/sdlc/decide.playbook/decide.registry.ts +7 -31
- package/reference/sdlc/review.md +4 -5
- package/reference/sdlc/review.playbook/review.fsm.d.ts +9 -11
- package/reference/sdlc/review.playbook/review.fsm.js +30 -24
- package/reference/sdlc/review.playbook/review.fsm.ts +39 -35
- package/reference/sdlc/review.playbook/review.gears.md +6 -5
- package/reference/sdlc/review.playbook/review.playbook.d.ts +2 -1
- package/reference/sdlc/review.playbook/review.playbook.js +16 -21
- package/reference/sdlc/review.playbook/review.playbook.ts +26 -26
- package/reference/sdlc/review.playbook/review.registry.d.ts +5 -13
- package/reference/sdlc/review.playbook/review.registry.js +3 -16
- package/reference/sdlc/review.playbook/review.registry.ts +7 -38
- package/slc/gears2fsm.md +27 -23
- package/slc/link.md +113 -93
- package/slc/text2gears.md +19 -18
- package/src/runtime.d.ts +20 -16
- package/src/runtime.ts +19 -23
- package/src/xstate-playbook-runtime.d.ts +21 -17
- package/src/xstate-playbook-runtime.js +241 -149
- package/src/xstate-playbook-runtime.ts +331 -178
- package/src/xstate-runtime.js +63 -24
- package/src/xstate-runtime.ts +96 -28
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { type XStatePromptIdentity } from '@sublang/playbook/xstate-runtime';
|
|
1
2
|
import { type PlayerInput, type ReviewInput } from './review.fsm.js';
|
|
2
3
|
import type { CaptainCallOptions, CaptainResult, JsonValue, NormalizedError, PlayerCallOptions, PlaybookCallRequest, PlaybookCallResult, PlaybookCallStart, PlaybookControlReceipt, PlaybookControlView, PlaybookPendingCall, PlaybookPorts, PlaybookRunResult, PlaybookRuntime, PlaybookRuntimeFactory, PlaybookRuntimeSnapshot, PlaybookSession, PlaybookState, PlaybookStateValue, PlaybookTraceEvent, PlaybookTraceType, PlayerResult, PlayerSessionStore } from '@sublang/playbook/runtime';
|
|
3
4
|
export type { CaptainCallOptions, CaptainResult, JsonValue, NormalizedError, PlayerCallOptions, PlaybookCallRequest, PlaybookCallResult, PlaybookCallStart, PlaybookControlReceipt, PlaybookControlView, PlaybookPendingCall, PlaybookPorts, PlaybookRunResult, PlaybookRuntime, PlaybookRuntimeFactory, PlaybookRuntimeSnapshot, PlaybookSession, PlaybookState, PlaybookStateValue, PlaybookTraceEvent, PlaybookTraceType, PlayerResult, PlayerSessionStore, };
|
|
4
5
|
export type ReviewPlaybookOptions = ReviewInput;
|
|
5
6
|
/** Keep every line of a relayed runtime value inside its authored quote. */
|
|
6
|
-
declare function composePlayerPrompt(input: PlayerInput): string;
|
|
7
|
+
declare function composePlayerPrompt(input: PlayerInput, promptIdentity: XStatePromptIdentity): string;
|
|
7
8
|
export declare const _internal: {
|
|
8
9
|
composePlayerPrompt: typeof composePlayerPrompt;
|
|
9
10
|
VERBATIM_PAYLOAD_FIELDS: ReadonlySet<string>;
|
|
@@ -3,15 +3,14 @@
|
|
|
3
3
|
//
|
|
4
4
|
// Generated by slc/link.md (FSM-to-Runtime linker).
|
|
5
5
|
// Source FSM: ./review.fsm.ts
|
|
6
|
-
//
|
|
6
|
+
// Role metadata: Coder→coder, Reviewer→reviewer (canonical local roles)
|
|
7
7
|
// Boss event: deterministic START_REVIEW entry; exact Boss text becomes
|
|
8
8
|
// callerInput; pending player questions retain BOSS_REPLY
|
|
9
9
|
// Adjudication: LLM judge per state; coderOutput and reviewerOutput are
|
|
10
10
|
// carried verbatim
|
|
11
|
-
// Compat: artifact schema
|
|
11
|
+
// Compat: artifact schema 2 / runtime ABI 1
|
|
12
12
|
import { RUNTIME_ABI, createXStatePlaybookRuntime, snapshotJsonValue, } from '@sublang/playbook/xstate-runtime';
|
|
13
13
|
import { reviewMachine, } from './review.fsm.js';
|
|
14
|
-
const OPTION_KEYS = new Set(['coderLlm', 'reviewerLlm']);
|
|
15
14
|
const PLACEHOLDER = /<(#|[A-Za-z_$][A-Za-z0-9_$-]*)>/g;
|
|
16
15
|
const CONTINUATION_PREAMBLE = 'You previously paused this task to ask Boss a question; Boss has now replied. Continue the same task using the reply below.';
|
|
17
16
|
const VERBATIM_PAYLOAD_FIELDS = new Set([
|
|
@@ -27,15 +26,7 @@ function snapshotReviewOptions(value) {
|
|
|
27
26
|
}
|
|
28
27
|
const record = captured;
|
|
29
28
|
for (const key of Object.keys(record)) {
|
|
30
|
-
|
|
31
|
-
throw new TypeError(`REVIEW runtime options.${key} is not declared`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
for (const key of OPTION_KEYS) {
|
|
35
|
-
const option = record[key];
|
|
36
|
-
if (typeof option !== 'string' || option.trim().length === 0) {
|
|
37
|
-
throw new TypeError(`REVIEW runtime options.${key} must be a non-empty string`);
|
|
38
|
-
}
|
|
29
|
+
throw new TypeError(`REVIEW runtime options.${key} is not declared`);
|
|
39
30
|
}
|
|
40
31
|
return captured;
|
|
41
32
|
}
|
|
@@ -48,10 +39,14 @@ function quotedContinuation(value) {
|
|
|
48
39
|
return value.replaceAll('\n', '\n> ');
|
|
49
40
|
}
|
|
50
41
|
/** Keep every line of a relayed runtime value inside its authored quote. */
|
|
51
|
-
function composePlayerPrompt(input) {
|
|
42
|
+
function composePlayerPrompt(input, promptIdentity) {
|
|
52
43
|
const fields = input;
|
|
53
44
|
const body = input.prompt.replace(PLACEHOLDER, (match, token, offset, source) => {
|
|
54
|
-
const value =
|
|
45
|
+
const value = token === 'coder-llm'
|
|
46
|
+
? promptIdentity('coder')
|
|
47
|
+
: token === 'reviewer-llm'
|
|
48
|
+
? promptIdentity('reviewer')
|
|
49
|
+
: fields[placeholderField(token)];
|
|
55
50
|
if (typeof value !== 'string')
|
|
56
51
|
return match;
|
|
57
52
|
const lineStart = source.lastIndexOf('\n', offset - 1) + 1;
|
|
@@ -76,28 +71,28 @@ export const _internal = {
|
|
|
76
71
|
};
|
|
77
72
|
const runtimeSpec = {
|
|
78
73
|
label: 'REVIEW',
|
|
79
|
-
compat: { artifactSchema:
|
|
74
|
+
compat: { artifactSchema: 2, runtimeAbi: RUNTIME_ABI },
|
|
80
75
|
snapshotOptions: snapshotReviewOptions,
|
|
81
76
|
entryEvent: { type: 'START_REVIEW', textField: 'callerInput' },
|
|
82
|
-
|
|
77
|
+
roleStates: {
|
|
83
78
|
reviewInitial: {
|
|
84
|
-
|
|
79
|
+
role: 'reviewer',
|
|
85
80
|
label: 'REVIEW-1: Reviewer examines the latest commit against the caller input.',
|
|
86
81
|
},
|
|
87
82
|
addressFindings: {
|
|
88
|
-
|
|
83
|
+
role: 'coder',
|
|
89
84
|
label: 'REVIEW-2: Coder accepts or rejects every current review finding.',
|
|
90
85
|
},
|
|
91
86
|
reviewAfterCommit: {
|
|
92
|
-
|
|
87
|
+
role: 'reviewer',
|
|
93
88
|
label: 'REVIEW-3: Reviewer examines the new review-fix commit and repository state.',
|
|
94
89
|
},
|
|
95
90
|
reviewAfterRebuttal: {
|
|
96
|
-
|
|
91
|
+
role: 'reviewer',
|
|
97
92
|
label: 'REVIEW-4: Reviewer adjudicates an all-rejected Coder disposition.',
|
|
98
93
|
},
|
|
99
94
|
},
|
|
100
|
-
composePlayerPrompt: (input) => composePlayerPrompt(input),
|
|
95
|
+
composePlayerPrompt: (input, promptIdentity) => composePlayerPrompt(input, promptIdentity),
|
|
101
96
|
verbatimPayloadFields: VERBATIM_PAYLOAD_FIELDS,
|
|
102
97
|
controlContextFields: [],
|
|
103
98
|
transitionEventFields: [
|
|
@@ -3,18 +3,19 @@
|
|
|
3
3
|
//
|
|
4
4
|
// Generated by slc/link.md (FSM-to-Runtime linker).
|
|
5
5
|
// Source FSM: ./review.fsm.ts
|
|
6
|
-
//
|
|
6
|
+
// Role metadata: Coder→coder, Reviewer→reviewer (canonical local roles)
|
|
7
7
|
// Boss event: deterministic START_REVIEW entry; exact Boss text becomes
|
|
8
8
|
// callerInput; pending player questions retain BOSS_REPLY
|
|
9
9
|
// Adjudication: LLM judge per state; coderOutput and reviewerOutput are
|
|
10
10
|
// carried verbatim
|
|
11
|
-
// Compat: artifact schema
|
|
11
|
+
// Compat: artifact schema 2 / runtime ABI 1
|
|
12
12
|
|
|
13
13
|
import {
|
|
14
14
|
RUNTIME_ABI,
|
|
15
15
|
createXStatePlaybookRuntime,
|
|
16
16
|
snapshotJsonValue,
|
|
17
17
|
type PlaybookPlayerInput,
|
|
18
|
+
type XStatePromptIdentity,
|
|
18
19
|
type XStatePlaybookRuntimeSpec,
|
|
19
20
|
} from '@sublang/playbook/xstate-runtime';
|
|
20
21
|
import {
|
|
@@ -76,7 +77,6 @@ export type {
|
|
|
76
77
|
|
|
77
78
|
export type ReviewPlaybookOptions = ReviewInput;
|
|
78
79
|
|
|
79
|
-
const OPTION_KEYS = new Set(['coderLlm', 'reviewerLlm']);
|
|
80
80
|
const PLACEHOLDER = /<(#|[A-Za-z_$][A-Za-z0-9_$-]*)>/g;
|
|
81
81
|
const CONTINUATION_PREAMBLE =
|
|
82
82
|
'You previously paused this task to ask Boss a question; Boss has now replied. Continue the same task using the reply below.';
|
|
@@ -97,17 +97,7 @@ function snapshotReviewOptions(value: unknown): ReviewPlaybookOptions {
|
|
|
97
97
|
}
|
|
98
98
|
const record = captured as Readonly<Record<string, JsonValue>>;
|
|
99
99
|
for (const key of Object.keys(record)) {
|
|
100
|
-
|
|
101
|
-
throw new TypeError(`REVIEW runtime options.${key} is not declared`);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
for (const key of OPTION_KEYS) {
|
|
105
|
-
const option = record[key];
|
|
106
|
-
if (typeof option !== 'string' || option.trim().length === 0) {
|
|
107
|
-
throw new TypeError(
|
|
108
|
-
`REVIEW runtime options.${key} must be a non-empty string`,
|
|
109
|
-
);
|
|
110
|
-
}
|
|
100
|
+
throw new TypeError(`REVIEW runtime options.${key} is not declared`);
|
|
111
101
|
}
|
|
112
102
|
return captured as unknown as ReviewPlaybookOptions;
|
|
113
103
|
}
|
|
@@ -124,12 +114,20 @@ function quotedContinuation(value: string): string {
|
|
|
124
114
|
}
|
|
125
115
|
|
|
126
116
|
/** Keep every line of a relayed runtime value inside its authored quote. */
|
|
127
|
-
function composePlayerPrompt(
|
|
117
|
+
function composePlayerPrompt(
|
|
118
|
+
input: PlayerInput,
|
|
119
|
+
promptIdentity: XStatePromptIdentity,
|
|
120
|
+
): string {
|
|
128
121
|
const fields = input as unknown as Record<string, unknown>;
|
|
129
122
|
const body = input.prompt.replace(
|
|
130
123
|
PLACEHOLDER,
|
|
131
124
|
(match: string, token: string, offset: number, source: string) => {
|
|
132
|
-
const value =
|
|
125
|
+
const value =
|
|
126
|
+
token === 'coder-llm'
|
|
127
|
+
? promptIdentity('coder')
|
|
128
|
+
: token === 'reviewer-llm'
|
|
129
|
+
? promptIdentity('reviewer')
|
|
130
|
+
: fields[placeholderField(token)];
|
|
133
131
|
if (typeof value !== 'string') return match;
|
|
134
132
|
const lineStart = source.lastIndexOf('\n', offset - 1) + 1;
|
|
135
133
|
return source.slice(lineStart, offset) === '> '
|
|
@@ -156,34 +154,36 @@ export const _internal = {
|
|
|
156
154
|
VERBATIM_PAYLOAD_FIELDS,
|
|
157
155
|
};
|
|
158
156
|
|
|
159
|
-
const runtimeSpec
|
|
157
|
+
const runtimeSpec = {
|
|
160
158
|
label: 'REVIEW',
|
|
161
|
-
compat: { artifactSchema:
|
|
159
|
+
compat: { artifactSchema: 2, runtimeAbi: RUNTIME_ABI },
|
|
162
160
|
snapshotOptions: snapshotReviewOptions,
|
|
163
161
|
entryEvent: { type: 'START_REVIEW', textField: 'callerInput' },
|
|
164
|
-
|
|
162
|
+
roleStates: {
|
|
165
163
|
reviewInitial: {
|
|
166
|
-
|
|
164
|
+
role: 'reviewer',
|
|
167
165
|
label:
|
|
168
166
|
'REVIEW-1: Reviewer examines the latest commit against the caller input.',
|
|
169
167
|
},
|
|
170
168
|
addressFindings: {
|
|
171
|
-
|
|
169
|
+
role: 'coder',
|
|
172
170
|
label: 'REVIEW-2: Coder accepts or rejects every current review finding.',
|
|
173
171
|
},
|
|
174
172
|
reviewAfterCommit: {
|
|
175
|
-
|
|
173
|
+
role: 'reviewer',
|
|
176
174
|
label:
|
|
177
175
|
'REVIEW-3: Reviewer examines the new review-fix commit and repository state.',
|
|
178
176
|
},
|
|
179
177
|
reviewAfterRebuttal: {
|
|
180
|
-
|
|
178
|
+
role: 'reviewer',
|
|
181
179
|
label:
|
|
182
180
|
'REVIEW-4: Reviewer adjudicates an all-rejected Coder disposition.',
|
|
183
181
|
},
|
|
184
182
|
},
|
|
185
|
-
composePlayerPrompt: (
|
|
186
|
-
|
|
183
|
+
composePlayerPrompt: (
|
|
184
|
+
input: PlaybookPlayerInput,
|
|
185
|
+
promptIdentity: XStatePromptIdentity,
|
|
186
|
+
) => composePlayerPrompt(input as PlayerInput, promptIdentity),
|
|
187
187
|
verbatimPayloadFields: VERBATIM_PAYLOAD_FIELDS,
|
|
188
188
|
controlContextFields: [],
|
|
189
189
|
transitionEventFields: [
|
|
@@ -193,7 +193,7 @@ const runtimeSpec: XStatePlaybookRuntimeSpec<ReviewPlaybookOptions> = {
|
|
|
193
193
|
'answer',
|
|
194
194
|
'questionId',
|
|
195
195
|
],
|
|
196
|
-
}
|
|
196
|
+
} satisfies XStatePlaybookRuntimeSpec<ReviewPlaybookOptions>;
|
|
197
197
|
|
|
198
198
|
const createPlaybookRuntime: PlaybookRuntimeFactory<ReviewPlaybookOptions> =
|
|
199
199
|
createXStatePlaybookRuntime(reviewMachine, runtimeSpec);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type PlaybookRuntime
|
|
1
|
+
import { type PlaybookRuntime } from './review.playbook.js';
|
|
2
2
|
export interface PlaybookSummaryPolicy {
|
|
3
3
|
stateCountLabels: Readonly<Record<string, string>>;
|
|
4
4
|
copyPasteGuardNames: readonly string[];
|
|
@@ -7,24 +7,17 @@ export interface PlaybookSummaryPolicy {
|
|
|
7
7
|
copyPastes: number;
|
|
8
8
|
}, rounds: number): string;
|
|
9
9
|
}
|
|
10
|
-
export interface RegistryPlayer {
|
|
11
|
-
id: string;
|
|
12
|
-
adapter?: string;
|
|
13
|
-
model?: string;
|
|
14
|
-
}
|
|
15
|
-
export interface CreateReviewRuntimeOptions {
|
|
16
|
-
captainOptions: unknown;
|
|
17
|
-
players: readonly RegistryPlayer[];
|
|
18
|
-
}
|
|
19
10
|
export type ReviewOptions = Readonly<Record<string, never>>;
|
|
20
11
|
export interface ReviewPlaybookRegistryEntry {
|
|
21
12
|
id: 'review';
|
|
22
13
|
command: 'review';
|
|
23
14
|
intent: string;
|
|
15
|
+
artifactSchema: 2;
|
|
24
16
|
requiredRoleIds: readonly ['coder', 'reviewer'];
|
|
17
|
+
concurrentRoleSets: readonly [];
|
|
25
18
|
summaryPolicy: PlaybookSummaryPolicy;
|
|
26
|
-
validateOptions(
|
|
27
|
-
createRuntime(options:
|
|
19
|
+
validateOptions(optionSlice: unknown): ReviewOptions;
|
|
20
|
+
createRuntime(options: ReviewOptions): PlaybookRuntime;
|
|
28
21
|
}
|
|
29
22
|
export declare const reviewStateCountLabels: {
|
|
30
23
|
readonly reviewInitial: "review round";
|
|
@@ -38,6 +31,5 @@ export declare function reviewSavedCountsLine(counts: {
|
|
|
38
31
|
}, rounds: number): string;
|
|
39
32
|
export declare const reviewSummaryPolicy: PlaybookSummaryPolicy;
|
|
40
33
|
export declare function validateReviewOptions(optionSlice: unknown): ReviewOptions;
|
|
41
|
-
export declare function createReviewRuntimeOptions({ captainOptions, players, }: CreateReviewRuntimeOptions): ReviewPlaybookOptions;
|
|
42
34
|
export declare const reviewPlaybookRegistryEntry: ReviewPlaybookRegistryEntry;
|
|
43
35
|
export default reviewPlaybookRegistryEntry;
|
|
@@ -44,30 +44,17 @@ export function validateReviewOptions(optionSlice) {
|
|
|
44
44
|
}
|
|
45
45
|
return Object.freeze({});
|
|
46
46
|
}
|
|
47
|
-
function playerIdentity(players, id) {
|
|
48
|
-
const player = players.find((entry) => entry.id === id);
|
|
49
|
-
const identity = player?.model ?? player?.adapter;
|
|
50
|
-
if (identity === undefined || identity.trim().length === 0) {
|
|
51
|
-
throw new Error(`REVIEW requires configured player ${id}`);
|
|
52
|
-
}
|
|
53
|
-
return identity;
|
|
54
|
-
}
|
|
55
|
-
export function createReviewRuntimeOptions({ captainOptions, players, }) {
|
|
56
|
-
validateReviewOptions(captainOptions);
|
|
57
|
-
return {
|
|
58
|
-
coderLlm: playerIdentity(players, 'coder'),
|
|
59
|
-
reviewerLlm: playerIdentity(players, 'reviewer'),
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
47
|
export const reviewPlaybookRegistryEntry = {
|
|
63
48
|
id: 'review',
|
|
64
49
|
command: 'review',
|
|
65
50
|
intent: 'review the latest commit until no material correctness or spec findings remain',
|
|
51
|
+
artifactSchema: 2,
|
|
66
52
|
requiredRoleIds: ['coder', 'reviewer'],
|
|
53
|
+
concurrentRoleSets: [],
|
|
67
54
|
summaryPolicy: reviewSummaryPolicy,
|
|
68
55
|
validateOptions: validateReviewOptions,
|
|
69
56
|
createRuntime(options) {
|
|
70
|
-
return createPlaybookRuntime(
|
|
57
|
+
return createPlaybookRuntime(options);
|
|
71
58
|
},
|
|
72
59
|
};
|
|
73
60
|
export default reviewPlaybookRegistryEntry;
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
|
|
4
4
|
import createPlaybookRuntime, {
|
|
5
5
|
type PlaybookRuntime,
|
|
6
|
-
type ReviewPlaybookOptions,
|
|
7
6
|
} from './review.playbook.js';
|
|
8
7
|
|
|
9
8
|
export interface PlaybookSummaryPolicy {
|
|
@@ -15,27 +14,18 @@ export interface PlaybookSummaryPolicy {
|
|
|
15
14
|
): string;
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
export interface RegistryPlayer {
|
|
19
|
-
id: string;
|
|
20
|
-
adapter?: string;
|
|
21
|
-
model?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface CreateReviewRuntimeOptions {
|
|
25
|
-
captainOptions: unknown;
|
|
26
|
-
players: readonly RegistryPlayer[];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
17
|
export type ReviewOptions = Readonly<Record<string, never>>;
|
|
30
18
|
|
|
31
19
|
export interface ReviewPlaybookRegistryEntry {
|
|
32
20
|
id: 'review';
|
|
33
21
|
command: 'review';
|
|
34
22
|
intent: string;
|
|
23
|
+
artifactSchema: 2;
|
|
35
24
|
requiredRoleIds: readonly ['coder', 'reviewer'];
|
|
25
|
+
concurrentRoleSets: readonly [];
|
|
36
26
|
summaryPolicy: PlaybookSummaryPolicy;
|
|
37
|
-
validateOptions(
|
|
38
|
-
createRuntime(options:
|
|
27
|
+
validateOptions(optionSlice: unknown): ReviewOptions;
|
|
28
|
+
createRuntime(options: ReviewOptions): PlaybookRuntime;
|
|
39
29
|
}
|
|
40
30
|
|
|
41
31
|
export const reviewStateCountLabels = {
|
|
@@ -99,39 +89,18 @@ export function validateReviewOptions(optionSlice: unknown): ReviewOptions {
|
|
|
99
89
|
return Object.freeze({});
|
|
100
90
|
}
|
|
101
91
|
|
|
102
|
-
function playerIdentity(
|
|
103
|
-
players: readonly RegistryPlayer[],
|
|
104
|
-
id: 'coder' | 'reviewer',
|
|
105
|
-
): string {
|
|
106
|
-
const player = players.find((entry) => entry.id === id);
|
|
107
|
-
const identity = player?.model ?? player?.adapter;
|
|
108
|
-
if (identity === undefined || identity.trim().length === 0) {
|
|
109
|
-
throw new Error(`REVIEW requires configured player ${id}`);
|
|
110
|
-
}
|
|
111
|
-
return identity;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function createReviewRuntimeOptions({
|
|
115
|
-
captainOptions,
|
|
116
|
-
players,
|
|
117
|
-
}: CreateReviewRuntimeOptions): ReviewPlaybookOptions {
|
|
118
|
-
validateReviewOptions(captainOptions);
|
|
119
|
-
return {
|
|
120
|
-
coderLlm: playerIdentity(players, 'coder'),
|
|
121
|
-
reviewerLlm: playerIdentity(players, 'reviewer'),
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
92
|
export const reviewPlaybookRegistryEntry: ReviewPlaybookRegistryEntry = {
|
|
126
93
|
id: 'review',
|
|
127
94
|
command: 'review',
|
|
128
95
|
intent:
|
|
129
96
|
'review the latest commit until no material correctness or spec findings remain',
|
|
97
|
+
artifactSchema: 2,
|
|
130
98
|
requiredRoleIds: ['coder', 'reviewer'],
|
|
99
|
+
concurrentRoleSets: [],
|
|
131
100
|
summaryPolicy: reviewSummaryPolicy,
|
|
132
101
|
validateOptions: validateReviewOptions,
|
|
133
102
|
createRuntime(options) {
|
|
134
|
-
return createPlaybookRuntime(
|
|
103
|
+
return createPlaybookRuntime(options);
|
|
135
104
|
},
|
|
136
105
|
};
|
|
137
106
|
|
package/slc/gears2fsm.md
CHANGED
|
@@ -36,7 +36,7 @@ map for every actor kind the GEARS artifact uses, using typed actor logic such
|
|
|
36
36
|
as `fromPromise<Output, Input>(...)` [[11]]:
|
|
37
37
|
|
|
38
38
|
- `captain` for direct work performed by Captain;
|
|
39
|
-
- `player` for work Captain delegates to a named
|
|
39
|
+
- `player` for work Captain delegates to a named role;
|
|
40
40
|
- `playbook` for a nested playbook call; and
|
|
41
41
|
- `script` for a deterministic shell script an
|
|
42
42
|
[optimizer-introduced script item](text2gears.md#script-behaviors-optimizer-introduced)
|
|
@@ -73,7 +73,7 @@ comment delimiters into a TypeScript target.
|
|
|
73
73
|
`PlayerInput` shall be a typed object with at least:
|
|
74
74
|
|
|
75
75
|
- `stateId`: the stable id of the invoking working leaf;
|
|
76
|
-
- `
|
|
76
|
+
- `role`: the canonical lowercase local id derived from the [role](text2gears.md#roles) Captain is to delegate;
|
|
77
77
|
- `sourceItem`: the GEARS item ID this state realizes;
|
|
78
78
|
- `prompt`: the source item's full final prompt, verbatim;
|
|
79
79
|
- `result`: a record whose keys are the valid guard names this invocation may return.
|
|
@@ -244,22 +244,22 @@ Each state shall declare:
|
|
|
244
244
|
- a stable `id` (for `#id` targeting and Boss interrupts);
|
|
245
245
|
- an intuitive state key (the property name under `states: { ... }`);
|
|
246
246
|
- a one-line `description` (for inspector tools and documentation);
|
|
247
|
-
- JSON-safe `meta: { playbook: { stateId, description,
|
|
247
|
+
- JSON-safe `meta: { playbook: { stateId, description, role? } }` repeating
|
|
248
248
|
its stable id and description so linked runtimes can discover active public
|
|
249
249
|
identities through `snapshot.getMeta()` without private XState nodes. A
|
|
250
|
-
delegated-
|
|
251
|
-
`meta.playbook.
|
|
250
|
+
delegated-role state shall also carry the canonical lowercase source role id in
|
|
251
|
+
`meta.playbook.role`; every other state shall omit `role`;
|
|
252
252
|
- if it invokes the direct `captain` actor: `invoke.input` carrying
|
|
253
253
|
`sourceItem`, `prompt`, and `result` (per [Setup](#setup));
|
|
254
254
|
- if it invokes the delegated `player` actor: `invoke.input` additionally
|
|
255
|
-
carrying the same source-derived `
|
|
255
|
+
carrying the same source-derived `role` as `meta.playbook.role`;
|
|
256
256
|
- if it invokes the `script` actor: `invoke.input` carrying `stateId`,
|
|
257
257
|
`sourceItem`, `command`, and `result` (per [Setup](#setup)) — no `prompt`
|
|
258
|
-
and no `
|
|
258
|
+
and no `role`.
|
|
259
259
|
|
|
260
260
|
The source item ID shall live in `invoke.input.sourceItem`, not in a comment — this keeps the GEARS-to-state mapping machine-readable.
|
|
261
|
-
A delegated state's `invoke.input.
|
|
262
|
-
|
|
261
|
+
A delegated state's `invoke.input.role` shall match the canonical lowercase id of its source item's named role.
|
|
262
|
+
A direct Captain state shall not invent a `Captain` role binding.
|
|
263
263
|
|
|
264
264
|
Every invoking working leaf — sequential or parallel, whatever its actor
|
|
265
265
|
kind — shall carry the tag `playbook.busy`: the shared quiescence helper
|
|
@@ -281,7 +281,7 @@ invoke: {
|
|
|
281
281
|
src: 'player',
|
|
282
282
|
input: ({ context }): PlayerInput => ({
|
|
283
283
|
stateId: '<stable-state-id>',
|
|
284
|
-
|
|
284
|
+
role: 'reviewer',
|
|
285
285
|
sourceItem: '<ITEM-A>',
|
|
286
286
|
prompt: [
|
|
287
287
|
'Flag any issues or improvements (numbered; no duplication).',
|
|
@@ -299,17 +299,17 @@ invoke: {
|
|
|
299
299
|
|
|
300
300
|
For an item in which Captain acts directly, the corresponding invocation uses
|
|
301
301
|
`src: 'captain'` and a `CaptainInput` with the same static mapping fields but no
|
|
302
|
-
`
|
|
302
|
+
`role` field.
|
|
303
303
|
|
|
304
304
|
## Mapping
|
|
305
305
|
|
|
306
306
|
Each Source spec item shall map to exactly one state in Target.
|
|
307
307
|
A state's `invoke.input.sourceItem` shall be that item's ID, and `invoke.input.prompt` shall carry the item's prompt verbatim.
|
|
308
308
|
|
|
309
|
-
An item written as direct Captain work shall map to exactly one `captain`
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
309
|
+
An item written as direct Captain work shall map to exactly one `captain` invocation.
|
|
310
|
+
An item that prompts or relays to a named role shall map to exactly one `player` invocation.
|
|
311
|
+
A nested-call item shall map to exactly one `playbook` invocation.
|
|
312
|
+
A script item (`Captain shall run:`) shall map to
|
|
313
313
|
exactly one `script` invocation whose `input.command` carries the blockquote
|
|
314
314
|
verbatim and whose `result` preserves the item's two guards in declared order.
|
|
315
315
|
The compiler shall not infer one actor kind from a
|
|
@@ -333,10 +333,14 @@ Each member shall be a delegated-player item; a direct-Captain or nested-call
|
|
|
333
333
|
member is malformed because those actor kinds share one Captain control lane or one
|
|
334
334
|
pending-child slot. Each region shall contain a delegated-player working leaf
|
|
335
335
|
and a local final state; the working leaf retains the item's stable state id,
|
|
336
|
-
`sourceItem`,
|
|
336
|
+
`sourceItem`, role, prompt, and result contract.
|
|
337
|
+
The members' canonical role ids shall be pairwise distinct; a repeated role in one group is malformed.
|
|
337
338
|
The parallel parent shall use `onDone` as the join, which XState takes only
|
|
338
339
|
after every region reaches final.
|
|
339
340
|
|
|
341
|
+
The artifact shall export `concurrentRoleSets` as a deeply readonly array containing one role-id array per parallel group in first-item source order, with each inner array following that group's item order.
|
|
342
|
+
An artifact with no parallel group shall export an empty array.
|
|
343
|
+
|
|
340
344
|
Each branch shall assign only its own staged result.
|
|
341
345
|
The join shall promote all staged results atomically before later work begins,
|
|
342
346
|
so branch completion order cannot change downstream inputs.
|
|
@@ -527,8 +531,8 @@ the number of sequential child calls without an arbitrary runtime call limit.
|
|
|
527
531
|
Prompts shall pass only the **specific extracted fields** the player needs.
|
|
528
532
|
The compiler shall not dump `JSON.stringify(lastResult)` or any opaque blob: it leaks internal `guard` strings, wastes tokens, and confuses the LLM.
|
|
529
533
|
|
|
530
|
-
Player bindings and
|
|
531
|
-
The artifact shall not bake
|
|
534
|
+
Player bindings and prompt identities shall enter only through `PlaybookSession.roleBindings` at runtime call, prompt, and trace boundaries.
|
|
535
|
+
The artifact shall not bake them into machine input, options, or context; model names and other host settings shall remain host policy rather than persisted FSM state.
|
|
532
536
|
Host-owned configuration such as an enabled-playbook catalog shall remain
|
|
533
537
|
immutable machine input/context for the session. Boss events and actor outputs
|
|
534
538
|
shall not carry, replace, append to, or otherwise overwrite that catalog.
|
|
@@ -585,7 +589,7 @@ Phases may set typed routing fields so terminal outcomes return to the originati
|
|
|
585
589
|
|
|
586
590
|
## Boss control
|
|
587
591
|
|
|
588
|
-
[Boss](text2gears.md#
|
|
592
|
+
[Boss](text2gears.md#roles) input enters the machine through three surfaces: pre-emptive interrupts on active states, typed entry events on idle or recoverable states, and Boss replies to delegated-role questions that suspended the FSM in a dedicated wait state.
|
|
589
593
|
|
|
590
594
|
### Boss interrupts
|
|
591
595
|
|
|
@@ -667,12 +671,12 @@ the colon as the JSON field name.
|
|
|
667
671
|
The linked runtime composes player prompts per [link.md "Player prompt composition"](link.md#player-prompt-composition), without adding a player-visible Boss-question instruction.
|
|
668
672
|
|
|
669
673
|
The question record shall be
|
|
670
|
-
`{ questionId, resumeStateId, sourceItem,
|
|
674
|
+
`{ questionId, resumeStateId, sourceItem, asker, question }`, where `asker` is exactly `{ kind: 'captain' }` or `{ kind: 'role', roleId }`.
|
|
671
675
|
`questionId` and `resumeStateId` shall both equal the stable working-leaf
|
|
672
676
|
`stateId`.
|
|
673
|
-
`questionId`, `resumeStateId`, and `sourceItem` shall come from the suspended
|
|
674
|
-
|
|
675
|
-
|
|
677
|
+
`questionId`, `resumeStateId`, and `sourceItem` shall come from the suspended working leaf's stable invocation metadata.
|
|
678
|
+
A delegated `PlayerInput` shall produce the role asker with its canonical local role id, while a direct-Captain state shall produce the Captain asker without inventing a role.
|
|
679
|
+
Only
|
|
676
680
|
`question` shall come from adjudicated actor output.
|
|
677
681
|
|
|
678
682
|
A machine with at most one active Captain or player task may use the scalar
|