@vimhead.dev/norn-cli 0.1.0-tip.35614826665.1 → 0.1.0-tip.35724621678.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/README.md +41 -13
- package/assets/docs/README.md +16 -16
- package/assets/docs/agents.md +23 -15
- package/assets/docs/cli.md +10 -8
- package/assets/docs/composition.md +7 -7
- package/assets/docs/persistence.md +22 -22
- package/assets/docs/projects.md +6 -6
- package/assets/docs/recovery.md +10 -10
- package/assets/docs/schemas.md +42 -36
- package/assets/docs/workflows.md +39 -32
- package/assets/examples/agent-then-analysis/input.json +3 -3
- package/assets/examples/agent-then-analysis/norn.project.json +2 -2
- package/assets/examples/agent-then-analysis/plugin.ts +37 -9
- package/assets/examples/caller-owned-routing/README.md +6 -6
- package/assets/examples/caller-owned-routing/assessment.ts +18 -4
- package/assets/examples/caller-owned-routing/contracts.ts +7 -2
- package/assets/examples/caller-owned-routing/input.json +12 -12
- package/assets/examples/caller-owned-routing/norn.project.json +2 -2
- package/assets/examples/caller-owned-routing/revision.ts +7 -2
- package/assets/examples/caller-owned-routing/router.ts +14 -3
- package/assets/examples/caller-selected-continuation/caller.ts +38 -12
- package/assets/examples/caller-selected-continuation/input.json +7 -7
- package/assets/examples/caller-selected-continuation/norn.project.json +2 -2
- package/assets/examples/caller-selected-continuation/producer.ts +10 -3
- package/assets/examples/coordinating-multiple-agents/README.md +6 -6
- package/assets/examples/coordinating-multiple-agents/input.json +20 -8
- package/assets/examples/coordinating-multiple-agents/norn.project.json +2 -2
- package/assets/examples/coordinating-multiple-agents/plugin.ts +165 -46
- package/assets/examples/coordinating-multiple-agents/queue-tools.ts +30 -7
- package/assets/examples/coordinating-multiple-agents/work-queue.ts +211 -63
- package/assets/examples/getting-started/norn.project.json +2 -2
- package/assets/examples/getting-started/plugin.ts +33 -13
- package/assets/examples/minimal-workflow/norn.project.json +2 -2
- package/assets/examples/minimal-workflow/plugin.ts +12 -3
- package/assets/examples/shared-state/README.md +6 -6
- package/assets/examples/shared-state/input.json +1 -1
- package/assets/examples/shared-state/norn.project.json +2 -2
- package/assets/examples/shared-state/plugin.ts +44 -15
- package/assets/examples/shared-state/shared-state.ts +46 -13
- package/assets/examples/shared-state/state-tools.ts +68 -16
- package/assets/examples/worktree-development-loop/README.md +12 -12
- package/assets/examples/worktree-development-loop/norn.project.json +7 -7
- package/assets/examples/worktree-development-loop/plugin.ts +7 -1
- package/assets/examples/worktree-development-loop/scope.ts +4 -1
- package/assets/examples/worktree-development-loop/shared/commands.ts +6 -2
- package/assets/examples/worktree-development-loop/workflows/development-loop/execute.ts +18 -4
- package/assets/examples/worktree-development-loop/workflows/development-loop/index.ts +4 -1
- package/assets/examples/worktree-development-loop/workflows/development-loop/repository.ts +11 -1
- package/assets/examples/worktree-development-loop/workflows/development-loop/schema.ts +6 -2
- package/assets/examples/worktree-development-loop/workflows/implementation/execute.ts +40 -10
- package/assets/examples/worktree-development-loop/workflows/implementation/index.ts +5 -1
- package/assets/examples/worktree-development-loop/workflows/planning/execute.ts +1 -1
- package/assets/examples/worktree-development-loop/workflows/planning/index.ts +5 -1
- package/assets/examples/worktree-development-loop/workflows/review/execute.ts +33 -9
- package/assets/examples/worktree-development-loop/workflows/review-router/execute.ts +51 -8
- package/assets/package.json +1 -1
- package/assets/packages/cli/src/build-info.ts +4 -1
- package/assets/packages/cli/src/bun/cli.ts +21 -5
- package/assets/packages/cli/src/cli.ts +585 -170
- package/assets/packages/cli/src/client.ts +194 -36
- package/assets/packages/cli/src/documentation.ts +135 -30
- package/assets/packages/cli/src/generated-build-info.ts +2 -2
- package/assets/packages/cli/src/internal/agent-directory.ts +7 -2
- package/assets/packages/cli/src/internal/agent-response-tool.ts +57 -15
- package/assets/packages/cli/src/internal/agents.ts +248 -60
- package/assets/packages/cli/src/internal/commands.ts +82 -20
- package/assets/packages/cli/src/internal/documentation-bundle.ts +44 -13
- package/assets/packages/cli/src/internal/engine.ts +396 -87
- package/assets/packages/cli/src/internal/errors.ts +13 -5
- package/assets/packages/cli/src/internal/execution-context.ts +20 -12
- package/assets/packages/cli/src/internal/file-coordinator.ts +95 -26
- package/assets/packages/cli/src/internal/file-names.ts +4 -1
- package/assets/packages/cli/src/internal/launch-request.ts +74 -22
- package/assets/packages/cli/src/internal/logs.ts +10 -2
- package/assets/packages/cli/src/internal/metrics.ts +247 -61
- package/assets/packages/cli/src/internal/pi-assets.ts +105 -23
- package/assets/packages/cli/src/internal/run-lease.ts +72 -22
- package/assets/packages/cli/src/internal/run-log.ts +49 -20
- package/assets/packages/cli/src/internal/run-names.ts +120 -12
- package/assets/packages/cli/src/internal/run-state.ts +306 -71
- package/assets/packages/cli/src/internal/run-store.ts +216 -53
- package/assets/packages/cli/src/internal/usage.ts +23 -7
- package/assets/packages/cli/src/internal/worker-directory.ts +9 -3
- package/assets/packages/cli/src/internal/workflow-registry.ts +281 -70
- package/assets/packages/cli/src/internal/working-directory.ts +2 -1
- package/assets/packages/cli/src/workflow-loader.ts +341 -74
- package/assets/packages/core/src/atomic-files.ts +13 -4
- package/assets/packages/core/src/workflow-transition.ts +13 -2
- package/assets/packages/sdk/src/api.ts +248 -80
- package/assets/packages/sdk/src/index.ts +6 -1
- package/assets/packages/sdk/src/schema.ts +75 -21
- package/assets/tests/workflow-ref.test.ts +242 -57
- package/bin/norn.mjs +13 -4
- package/dist/cli.js +344 -90
- package/dist/client.js +100 -22
- package/dist/documentation.js +102 -25
- package/dist/generated-build-info.d.ts +2 -2
- package/dist/generated-build-info.js +2 -2
- package/dist/internal/agent-directory.js +3 -1
- package/dist/internal/agent-response-tool.js +42 -11
- package/dist/internal/agents.js +149 -37
- package/dist/internal/commands.js +65 -16
- package/dist/internal/documentation-bundle.js +23 -11
- package/dist/internal/engine.js +304 -66
- package/dist/internal/errors.js +4 -2
- package/dist/internal/execution-context.js +2 -1
- package/dist/internal/file-coordinator.js +59 -19
- package/dist/internal/launch-request.js +32 -14
- package/dist/internal/metrics.js +138 -38
- package/dist/internal/pi-assets.js +70 -19
- package/dist/internal/run-lease.js +29 -9
- package/dist/internal/run-log.js +24 -12
- package/dist/internal/run-state.js +172 -48
- package/dist/internal/run-store.js +157 -45
- package/dist/internal/worker-directory.js +6 -2
- package/dist/internal/workflow-registry.js +123 -32
- package/dist/internal/working-directory.js +2 -1
- package/dist/workflow-loader.js +198 -41
- package/package.json +2 -2
|
@@ -1,9 +1,24 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
CreateAgentSessionOptions,
|
|
3
|
+
EventBus,
|
|
4
|
+
PromptOptions,
|
|
5
|
+
ToolDefinition,
|
|
6
|
+
} from "@earendil-works/pi-coding-agent";
|
|
7
|
+
import {
|
|
8
|
+
Type,
|
|
9
|
+
type StaticDecode,
|
|
10
|
+
type StaticEncode,
|
|
11
|
+
type TCodec,
|
|
12
|
+
type TSchema,
|
|
13
|
+
} from "typebox";
|
|
3
14
|
import type { TLocalizedValidationError } from "typebox/error";
|
|
4
15
|
import { createWorkflowTransition } from "@vimhead.dev/norn-core/workflow-transition";
|
|
5
16
|
import { Value } from "typebox/value";
|
|
6
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
assertWorkflowMetadata,
|
|
19
|
+
isPlainObject,
|
|
20
|
+
jsonValueSchema,
|
|
21
|
+
} from "./schema.ts";
|
|
7
22
|
|
|
8
23
|
const WORKFLOW_DECLARATION_KIND = "norn.workflow";
|
|
9
24
|
|
|
@@ -27,7 +42,8 @@ export type NornWorkflowDeclaration<
|
|
|
27
42
|
Id extends string = string,
|
|
28
43
|
ArgsSchema extends TSchema = TSchema,
|
|
29
44
|
ConfigSchema extends TSchema | undefined = TSchema | undefined,
|
|
30
|
-
Scope extends NornWorkflowScopeInfo | undefined =
|
|
45
|
+
Scope extends NornWorkflowScopeInfo | undefined =
|
|
46
|
+
NornWorkflowScopeInfo | undefined,
|
|
31
47
|
> = {
|
|
32
48
|
(args: StaticEncode<ArgsSchema>): NornRunNext;
|
|
33
49
|
readonly kind: typeof WORKFLOW_DECLARATION_KIND;
|
|
@@ -35,43 +51,66 @@ export type NornWorkflowDeclaration<
|
|
|
35
51
|
readonly entrypoint: NornWorkflowEntrypoint;
|
|
36
52
|
readonly args: ArgsSchema;
|
|
37
53
|
readonly gate?: NornWorkflowGate<ArgsSchema> & {
|
|
38
|
-
describe?(
|
|
54
|
+
describe?(
|
|
55
|
+
context: NornWorkflowContext<ArgsSchema, ConfigSchema, Scope>,
|
|
56
|
+
): MaybePromise<string>;
|
|
39
57
|
};
|
|
40
58
|
readonly config?: ConfigSchema;
|
|
41
59
|
readonly scope: Scope;
|
|
42
|
-
execute(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
export type
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
execute(
|
|
61
|
+
context: NornWorkflowContext<ArgsSchema, ConfigSchema, Scope>,
|
|
62
|
+
): MaybePromise<WorkflowResult>;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type NornAnyWorkflowDeclaration = Pick<
|
|
66
|
+
NornWorkflowDeclaration,
|
|
67
|
+
keyof NornWorkflowDeclaration
|
|
68
|
+
> &
|
|
69
|
+
((args: never) => NornRunNext);
|
|
70
|
+
export type NornWorkflowRefSchemaOptions<ArgsSchema extends TSchema = TSchema> =
|
|
71
|
+
{
|
|
72
|
+
readonly args?: ArgsSchema;
|
|
73
|
+
};
|
|
74
|
+
export type NornWorkflowRefInput = StaticEncode<
|
|
75
|
+
typeof workflowReferenceInputSchema
|
|
76
|
+
>;
|
|
77
|
+
export type NornWorkflowRefOutput<ArgsSchema extends TSchema> = (
|
|
78
|
+
args: StaticEncode<ArgsSchema> & object,
|
|
79
|
+
) => NornRunNext;
|
|
80
|
+
|
|
81
|
+
export type NornWorkflowArgsInput<
|
|
82
|
+
TWorkflow extends NornAnyWorkflowDeclaration,
|
|
83
|
+
> = StaticEncode<TWorkflow["args"]>;
|
|
84
|
+
export type NornWorkflowArgs<TWorkflow extends NornAnyWorkflowDeclaration> =
|
|
85
|
+
StaticDecode<TWorkflow["args"]>;
|
|
86
|
+
|
|
87
|
+
export type NornWorkflowGate<ArgsSchema extends TSchema> =
|
|
88
|
+
unknown extends StaticEncode<ArgsSchema>
|
|
89
|
+
? NornWorkflowAnyGate
|
|
90
|
+
: StaticEncode<ArgsSchema> extends Record<string, unknown>
|
|
91
|
+
? {
|
|
92
|
+
readonly enabled: true;
|
|
93
|
+
readonly fields?: readonly Extract<
|
|
94
|
+
keyof StaticEncode<ArgsSchema>,
|
|
95
|
+
string
|
|
96
|
+
>[];
|
|
97
|
+
}
|
|
98
|
+
: {
|
|
99
|
+
readonly enabled: true;
|
|
100
|
+
readonly fields?: never;
|
|
101
|
+
};
|
|
66
102
|
|
|
67
103
|
export type NornWorkflowEntrypoint = false | { readonly instructions: string };
|
|
68
104
|
|
|
69
|
-
type WorkflowConfig<Schema extends TSchema | undefined> = Schema extends TSchema
|
|
105
|
+
type WorkflowConfig<Schema extends TSchema | undefined> = Schema extends TSchema
|
|
106
|
+
? StaticDecode<Schema>
|
|
107
|
+
: undefined;
|
|
70
108
|
|
|
71
109
|
export type NornWorkflowContext<
|
|
72
110
|
ArgsSchema extends TSchema = TSchema,
|
|
73
111
|
ConfigSchema extends TSchema | undefined = TSchema | undefined,
|
|
74
|
-
Scope extends NornWorkflowScopeInfo | undefined =
|
|
112
|
+
Scope extends NornWorkflowScopeInfo | undefined =
|
|
113
|
+
NornWorkflowScopeInfo | undefined,
|
|
75
114
|
> = {
|
|
76
115
|
readonly args: StaticDecode<ArgsSchema>;
|
|
77
116
|
readonly config: WorkflowConfig<ConfigSchema>;
|
|
@@ -80,9 +119,14 @@ export type NornWorkflowContext<
|
|
|
80
119
|
readonly commands: NornCommands;
|
|
81
120
|
readonly logs: NornLogs;
|
|
82
121
|
readonly run: NornRun;
|
|
83
|
-
} & (Scope extends NornWorkflowScopeInfo
|
|
84
|
-
|
|
85
|
-
|
|
122
|
+
} & (Scope extends NornWorkflowScopeInfo
|
|
123
|
+
? {
|
|
124
|
+
readonly scope: {
|
|
125
|
+
readonly id: Scope["id"];
|
|
126
|
+
readonly config: WorkflowConfig<Scope["config"]>;
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
: {});
|
|
86
130
|
|
|
87
131
|
export type NornWorkflowDefinition<
|
|
88
132
|
Name extends string = string,
|
|
@@ -95,9 +139,13 @@ export type NornWorkflowDefinition<
|
|
|
95
139
|
readonly args: ArgsSchema;
|
|
96
140
|
readonly config?: ConfigSchema;
|
|
97
141
|
readonly gate?: NornWorkflowGate<ArgsSchema> & {
|
|
98
|
-
describe?(
|
|
142
|
+
describe?(
|
|
143
|
+
context: NornWorkflowContext<ArgsSchema, ConfigSchema, Scope>,
|
|
144
|
+
): MaybePromise<string>;
|
|
99
145
|
};
|
|
100
|
-
execute(
|
|
146
|
+
execute(
|
|
147
|
+
context: NornWorkflowContext<ArgsSchema, ConfigSchema, Scope>,
|
|
148
|
+
): MaybePromise<WorkflowResult>;
|
|
101
149
|
};
|
|
102
150
|
|
|
103
151
|
export type NornWorkflowScopeInfo = {
|
|
@@ -105,48 +153,93 @@ export type NornWorkflowScopeInfo = {
|
|
|
105
153
|
readonly config?: TSchema;
|
|
106
154
|
};
|
|
107
155
|
|
|
108
|
-
export type NornWorkflowScope<
|
|
156
|
+
export type NornWorkflowScope<
|
|
157
|
+
Name extends string,
|
|
158
|
+
ConfigSchema extends TSchema | undefined,
|
|
159
|
+
> = {
|
|
109
160
|
readonly id: Name;
|
|
110
161
|
readonly config: ConfigSchema;
|
|
111
|
-
workflow<
|
|
112
|
-
|
|
113
|
-
|
|
162
|
+
workflow<
|
|
163
|
+
const LocalName extends string,
|
|
164
|
+
ArgsSchema extends TSchema,
|
|
165
|
+
LocalConfig extends TSchema | undefined = undefined,
|
|
166
|
+
>(
|
|
167
|
+
definition: NornWorkflowDefinition<
|
|
168
|
+
LocalName,
|
|
169
|
+
ArgsSchema,
|
|
170
|
+
LocalConfig,
|
|
171
|
+
{ readonly id: Name; readonly config: ConfigSchema }
|
|
172
|
+
>,
|
|
173
|
+
): NornWorkflowDeclaration<
|
|
174
|
+
`${Name}.${LocalName}`,
|
|
175
|
+
ArgsSchema,
|
|
176
|
+
LocalConfig,
|
|
177
|
+
{ readonly id: Name; readonly config: ConfigSchema }
|
|
178
|
+
>;
|
|
114
179
|
};
|
|
115
180
|
|
|
116
181
|
export function workflow<
|
|
117
182
|
const Name extends string,
|
|
118
183
|
ArgsSchema extends TSchema,
|
|
119
184
|
ConfigSchema extends TSchema | undefined = undefined,
|
|
120
|
-
>(
|
|
185
|
+
>(
|
|
186
|
+
definition: NornWorkflowDefinition<Name, ArgsSchema, ConfigSchema>,
|
|
187
|
+
): NornWorkflowDeclaration<Name, ArgsSchema, ConfigSchema, undefined> {
|
|
121
188
|
return createWorkflow({ definition, id: definition.name, scope: undefined });
|
|
122
189
|
}
|
|
123
190
|
|
|
124
|
-
function createWorkflow<
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
191
|
+
function createWorkflow<
|
|
192
|
+
Id extends string,
|
|
193
|
+
ArgsSchema extends TSchema,
|
|
194
|
+
ConfigSchema extends TSchema | undefined,
|
|
195
|
+
Scope extends NornWorkflowScopeInfo | undefined,
|
|
196
|
+
>(input: {
|
|
197
|
+
readonly definition: NornWorkflowDefinition<
|
|
198
|
+
string,
|
|
199
|
+
ArgsSchema,
|
|
200
|
+
ConfigSchema,
|
|
201
|
+
Scope
|
|
202
|
+
>;
|
|
203
|
+
readonly id: Id;
|
|
204
|
+
readonly scope: Scope;
|
|
205
|
+
}): NornWorkflowDeclaration<Id, ArgsSchema, ConfigSchema, Scope> {
|
|
206
|
+
const {
|
|
207
|
+
definition: { name, ...properties },
|
|
208
|
+
id,
|
|
209
|
+
scope,
|
|
210
|
+
} = input;
|
|
128
211
|
assertDeclarationName(name);
|
|
129
|
-
const callable = (args: StaticEncode<ArgsSchema>): NornRunNext =>
|
|
212
|
+
const callable = (args: StaticEncode<ArgsSchema>): NornRunNext =>
|
|
213
|
+
createWorkflowTransition({ workflowId: id, args });
|
|
130
214
|
const result = Object.assign(callable, properties, {
|
|
131
215
|
kind: WORKFLOW_DECLARATION_KIND,
|
|
132
216
|
id,
|
|
133
217
|
scope,
|
|
134
218
|
}) as NornWorkflowDeclaration<Id, ArgsSchema, ConfigSchema, Scope>;
|
|
135
219
|
assertWorkflowMetadata(result);
|
|
136
|
-
if (!isWorkflowDeclaration(result))
|
|
220
|
+
if (!isWorkflowDeclaration(result))
|
|
221
|
+
throw new Error(`Invalid workflow definition: ${id}`);
|
|
137
222
|
return result;
|
|
138
223
|
}
|
|
139
224
|
|
|
140
|
-
export function workflowScope<
|
|
141
|
-
|
|
142
|
-
|
|
225
|
+
export function workflowScope<
|
|
226
|
+
const Name extends string,
|
|
227
|
+
ConfigSchema extends TSchema | undefined = undefined,
|
|
228
|
+
>(input: {
|
|
229
|
+
readonly name: Name;
|
|
230
|
+
readonly config?: ConfigSchema;
|
|
231
|
+
}): NornWorkflowScope<Name, ConfigSchema> {
|
|
143
232
|
assertDeclarationName(input.name);
|
|
144
233
|
const scope = { id: input.name, config: input.config as ConfigSchema };
|
|
145
234
|
return {
|
|
146
235
|
id: scope.id,
|
|
147
236
|
config: scope.config,
|
|
148
237
|
workflow(definition) {
|
|
149
|
-
return createWorkflow({
|
|
238
|
+
return createWorkflow({
|
|
239
|
+
definition,
|
|
240
|
+
id: `${scope.id}.${definition.name}`,
|
|
241
|
+
scope,
|
|
242
|
+
});
|
|
150
243
|
},
|
|
151
244
|
};
|
|
152
245
|
}
|
|
@@ -237,9 +330,20 @@ export type NornInterruptedRunResult = {
|
|
|
237
330
|
readonly interruption: NornRunInterruption;
|
|
238
331
|
};
|
|
239
332
|
|
|
240
|
-
export type NornRunResult =
|
|
241
|
-
|
|
242
|
-
|
|
333
|
+
export type NornRunResult =
|
|
334
|
+
| NornStartedRunResult
|
|
335
|
+
| NornCompletedRunResult
|
|
336
|
+
| NornFailedRunResult
|
|
337
|
+
| NornStoppedRunResult
|
|
338
|
+
| NornInterruptedRunResult;
|
|
339
|
+
|
|
340
|
+
export type NornRunStatus =
|
|
341
|
+
| "running"
|
|
342
|
+
| "interrupted"
|
|
343
|
+
| "stopped"
|
|
344
|
+
| "pendingResume"
|
|
345
|
+
| "completed"
|
|
346
|
+
| "failed";
|
|
243
347
|
export type NornRunHealth = "healthy" | "unhealthy";
|
|
244
348
|
|
|
245
349
|
export type NornRunOutcomeInfo = {
|
|
@@ -298,21 +402,40 @@ export type NornCommandRunInput = {
|
|
|
298
402
|
const emptyWorkflowRefArgsSchema = Type.Object({});
|
|
299
403
|
const workflowReferenceInputSchema = Type.Union([
|
|
300
404
|
Type.String({ minLength: 1 }),
|
|
301
|
-
Type.Object({
|
|
405
|
+
Type.Object({
|
|
406
|
+
workflow: Type.String({ minLength: 1 }),
|
|
407
|
+
forwardArgs: Type.Record(Type.String(), Type.Unknown()),
|
|
408
|
+
}),
|
|
302
409
|
]);
|
|
303
410
|
|
|
304
|
-
export function workflowRefSchema<
|
|
411
|
+
export function workflowRefSchema<
|
|
412
|
+
ArgsSchema extends TSchema = typeof emptyWorkflowRefArgsSchema,
|
|
413
|
+
>(
|
|
414
|
+
options?: NornWorkflowRefSchemaOptions<ArgsSchema>,
|
|
415
|
+
): TCodec<
|
|
416
|
+
typeof workflowReferenceInputSchema,
|
|
417
|
+
NornWorkflowRefOutput<ArgsSchema>
|
|
418
|
+
> {
|
|
305
419
|
const contributionSchema = options?.args ?? emptyWorkflowRefArgsSchema;
|
|
306
|
-
return Type.With(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
420
|
+
return Type.With(
|
|
421
|
+
Type.Decode(workflowReferenceInputSchema, (reference) => {
|
|
422
|
+
const workflowId =
|
|
423
|
+
typeof reference === "string" ? reference : reference.workflow;
|
|
424
|
+
const forwardArgs =
|
|
425
|
+
typeof reference === "string" ? {} : reference.forwardArgs;
|
|
426
|
+
return (args: StaticEncode<ArgsSchema> & object): NornRunNext => {
|
|
427
|
+
Value.Assert(contributionSchema, args);
|
|
428
|
+
if (!isPlainObject(args))
|
|
429
|
+
throw new Error("Workflow reference contributions must be objects");
|
|
430
|
+
Value.Assert(jsonValueSchema, args);
|
|
431
|
+
return createWorkflowTransition({
|
|
432
|
+
workflowId,
|
|
433
|
+
args: { ...forwardArgs, ...args },
|
|
434
|
+
});
|
|
435
|
+
};
|
|
436
|
+
}),
|
|
437
|
+
{ "x-norn-workflow-ref": { contributedArgsSchema: contributionSchema } },
|
|
438
|
+
);
|
|
316
439
|
}
|
|
317
440
|
|
|
318
441
|
export type NornLogRef = {
|
|
@@ -340,7 +463,9 @@ export type NornAgentCreateSessionInput = {
|
|
|
340
463
|
readonly label: string;
|
|
341
464
|
readonly cwd: string;
|
|
342
465
|
readonly tools?: string[];
|
|
343
|
-
readonly beforeSessionStart?: (
|
|
466
|
+
readonly beforeSessionStart?: (
|
|
467
|
+
context: NornAgentBeforeSessionStartContext,
|
|
468
|
+
) => MaybePromise<void>;
|
|
344
469
|
readonly model?: CreateAgentSessionOptions["model"];
|
|
345
470
|
readonly thinkingLevel?: CreateAgentSessionOptions["thinkingLevel"];
|
|
346
471
|
readonly systemPrompt?: string;
|
|
@@ -354,7 +479,8 @@ export type NornAgentPromptInput<ResponseSchema extends TSchema> = {
|
|
|
354
479
|
readonly options?: PromptOptions;
|
|
355
480
|
};
|
|
356
481
|
|
|
357
|
-
export type NornAgentSinglePromptInput<ResponseSchema extends TSchema> =
|
|
482
|
+
export type NornAgentSinglePromptInput<ResponseSchema extends TSchema> =
|
|
483
|
+
NornAgentCreateSessionInput & NornAgentPromptInput<ResponseSchema>;
|
|
358
484
|
|
|
359
485
|
export type NornAgentSessionEvents = EventBus;
|
|
360
486
|
|
|
@@ -459,7 +585,9 @@ export type NornAgentSession = {
|
|
|
459
585
|
readonly label: string;
|
|
460
586
|
readonly cwd: string;
|
|
461
587
|
readonly events: NornAgentSessionEvents;
|
|
462
|
-
prompt<ResponseSchema extends TSchema>(
|
|
588
|
+
prompt<ResponseSchema extends TSchema>(
|
|
589
|
+
input: NornAgentPromptInput<ResponseSchema>,
|
|
590
|
+
): Promise<StaticDecode<ResponseSchema>>;
|
|
463
591
|
dispose(): Promise<void>;
|
|
464
592
|
};
|
|
465
593
|
|
|
@@ -467,7 +595,9 @@ export type NornRun = {
|
|
|
467
595
|
id: string;
|
|
468
596
|
next(workflowId: string, args: unknown): NornRunNext;
|
|
469
597
|
complete(metadata?: NornRunOutcomeMetadata): NornRunComplete;
|
|
470
|
-
fail(
|
|
598
|
+
fail(
|
|
599
|
+
metadata: NornRunOutcomeMetadata & { readonly summary: string },
|
|
600
|
+
): NornRunFail;
|
|
471
601
|
};
|
|
472
602
|
|
|
473
603
|
export type NornLogs = {
|
|
@@ -480,7 +610,9 @@ export type NornCommands = {
|
|
|
480
610
|
|
|
481
611
|
export type NornAgents = {
|
|
482
612
|
createSession(input: NornAgentCreateSessionInput): Promise<NornAgentSession>;
|
|
483
|
-
prompt<ResponseSchema extends TSchema>(
|
|
613
|
+
prompt<ResponseSchema extends TSchema>(
|
|
614
|
+
input: NornAgentSinglePromptInput<ResponseSchema>,
|
|
615
|
+
): Promise<StaticDecode<ResponseSchema>>;
|
|
484
616
|
};
|
|
485
617
|
|
|
486
618
|
export type NornWorkflowSource = {
|
|
@@ -505,7 +637,11 @@ export type NornRegisteredWorkflowInfo = {
|
|
|
505
637
|
};
|
|
506
638
|
|
|
507
639
|
export type NornInspectedWorkflowInfo = NornRegisteredWorkflowInfo & {
|
|
508
|
-
readonly scope?: {
|
|
640
|
+
readonly scope?: {
|
|
641
|
+
readonly id: string;
|
|
642
|
+
readonly configKey: string;
|
|
643
|
+
readonly configSchema: NornJsonSchema | null;
|
|
644
|
+
};
|
|
509
645
|
readonly argsSchema: NornJsonSchema;
|
|
510
646
|
readonly configSchema: NornJsonSchema | null;
|
|
511
647
|
readonly gate: NornWorkflowGateInfo | null;
|
|
@@ -557,17 +693,34 @@ export type NornProjectInfo = {
|
|
|
557
693
|
};
|
|
558
694
|
|
|
559
695
|
function assertDeclarationName(name: string): void {
|
|
560
|
-
if (
|
|
696
|
+
if (
|
|
697
|
+
typeof name !== "string" ||
|
|
698
|
+
name.trim().length === 0 ||
|
|
699
|
+
name.includes(".")
|
|
700
|
+
)
|
|
701
|
+
throw new Error(
|
|
702
|
+
`Invalid workflow or scope name: ${name}; expected a nonempty name without dots`,
|
|
703
|
+
);
|
|
561
704
|
}
|
|
562
705
|
|
|
563
|
-
export function isWorkflowDeclaration(
|
|
706
|
+
export function isWorkflowDeclaration(
|
|
707
|
+
value: unknown,
|
|
708
|
+
): value is NornAnyWorkflowDeclaration {
|
|
564
709
|
if (typeof value !== "function") return false;
|
|
565
|
-
const candidate = value as {
|
|
710
|
+
const candidate = value as {
|
|
711
|
+
kind?: unknown;
|
|
712
|
+
id?: unknown;
|
|
713
|
+
entrypoint?: unknown;
|
|
714
|
+
args?: unknown;
|
|
715
|
+
execute?: unknown;
|
|
716
|
+
};
|
|
566
717
|
return (
|
|
567
718
|
candidate.kind === WORKFLOW_DECLARATION_KIND &&
|
|
568
719
|
typeof candidate.id === "string" &&
|
|
569
720
|
candidate.id.length > 0 &&
|
|
570
|
-
(candidate.entrypoint === false ||
|
|
721
|
+
(candidate.entrypoint === false ||
|
|
722
|
+
(isPlainObject(candidate.entrypoint) &&
|
|
723
|
+
typeof candidate.entrypoint.instructions === "string")) &&
|
|
571
724
|
Boolean(candidate.args) &&
|
|
572
725
|
typeof candidate.execute === "function"
|
|
573
726
|
);
|
|
@@ -575,8 +728,16 @@ export function isWorkflowDeclaration(value: unknown): value is NornAnyWorkflowD
|
|
|
575
728
|
|
|
576
729
|
export function isWorkflowNext(value: unknown): value is NornRunNext {
|
|
577
730
|
if (!value || typeof value !== "object") return false;
|
|
578
|
-
const candidate = value as {
|
|
579
|
-
|
|
731
|
+
const candidate = value as {
|
|
732
|
+
type?: unknown;
|
|
733
|
+
workflowId?: unknown;
|
|
734
|
+
args?: unknown;
|
|
735
|
+
};
|
|
736
|
+
return (
|
|
737
|
+
candidate.type === "next" &&
|
|
738
|
+
typeof candidate.workflowId === "string" &&
|
|
739
|
+
candidate.workflowId.length > 0
|
|
740
|
+
);
|
|
580
741
|
}
|
|
581
742
|
|
|
582
743
|
export function isWorkflowComplete(value: unknown): value is NornRunComplete {
|
|
@@ -587,6 +748,13 @@ export function isWorkflowComplete(value: unknown): value is NornRunComplete {
|
|
|
587
748
|
|
|
588
749
|
export function isWorkflowFail(value: unknown): value is NornRunFail {
|
|
589
750
|
if (!value || typeof value !== "object") return false;
|
|
590
|
-
const candidate = value as {
|
|
591
|
-
|
|
751
|
+
const candidate = value as {
|
|
752
|
+
type?: unknown;
|
|
753
|
+
metadata?: { summary?: unknown };
|
|
754
|
+
};
|
|
755
|
+
return (
|
|
756
|
+
candidate.type === "fail" &&
|
|
757
|
+
typeof candidate.metadata?.summary === "string" &&
|
|
758
|
+
candidate.metadata.summary.length > 0
|
|
759
|
+
);
|
|
592
760
|
}
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
export type {
|
|
1
|
+
export type {
|
|
2
|
+
CreateAgentSessionOptions,
|
|
3
|
+
EventBus,
|
|
4
|
+
PromptOptions,
|
|
5
|
+
ToolDefinition,
|
|
6
|
+
} from "@earendil-works/pi-coding-agent";
|
|
2
7
|
export * from "./api.ts";
|
|
@@ -3,20 +3,32 @@ import { Meta } from "typebox/schema";
|
|
|
3
3
|
import { Value } from "typebox/value";
|
|
4
4
|
import type { NornAnyWorkflowDeclaration, NornJsonSchema } from "./api.ts";
|
|
5
5
|
|
|
6
|
-
export const jsonValueSchema = Type.Cyclic(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
export const jsonValueSchema = Type.Cyclic(
|
|
7
|
+
{
|
|
8
|
+
Json: Type.Union([
|
|
9
|
+
Type.Null(),
|
|
10
|
+
Type.Boolean(),
|
|
11
|
+
Type.Number(),
|
|
12
|
+
Type.String(),
|
|
13
|
+
Type.Array(Type.Ref("Json")),
|
|
14
|
+
Type.Refine(
|
|
15
|
+
Type.Record(Type.String(), Type.Ref("Json")),
|
|
16
|
+
(value) =>
|
|
17
|
+
Object.getPrototypeOf(value) === Object.prototype ||
|
|
18
|
+
Object.getPrototypeOf(value) === null,
|
|
19
|
+
),
|
|
20
|
+
]),
|
|
21
|
+
},
|
|
22
|
+
"Json",
|
|
23
|
+
);
|
|
13
24
|
|
|
14
25
|
export type NornJsonValue = Static<typeof jsonValueSchema>;
|
|
15
26
|
|
|
16
27
|
export function inspectSchema(schema: TSchema): NornJsonSchema {
|
|
17
28
|
const inspected: unknown = JSON.parse(JSON.stringify(schema));
|
|
18
29
|
Value.Assert(Meta["https://json-schema.org/draft/2020-12/schema"], inspected);
|
|
19
|
-
if (!isPlainObject(inspected))
|
|
30
|
+
if (!isPlainObject(inspected))
|
|
31
|
+
throw new Error("Norn inspection requires an object schema");
|
|
20
32
|
assertWorkflowReferenceAnnotations(inspected);
|
|
21
33
|
return inspected;
|
|
22
34
|
}
|
|
@@ -25,35 +37,73 @@ function assertWorkflowReferenceAnnotations(schema: unknown): void {
|
|
|
25
37
|
if (!isPlainObject(schema)) return;
|
|
26
38
|
if (Object.hasOwn(schema, "x-norn-workflow-ref")) {
|
|
27
39
|
const annotation = schema["x-norn-workflow-ref"];
|
|
28
|
-
if (
|
|
29
|
-
|
|
40
|
+
if (
|
|
41
|
+
!isPlainObject(annotation) ||
|
|
42
|
+
!Object.hasOwn(annotation, "contributedArgsSchema")
|
|
43
|
+
)
|
|
44
|
+
throw new Error("Invalid workflow reference annotation");
|
|
45
|
+
Value.Assert(
|
|
46
|
+
Meta["https://json-schema.org/draft/2020-12/schema"],
|
|
47
|
+
annotation.contributedArgsSchema,
|
|
48
|
+
);
|
|
30
49
|
assertWorkflowReferenceAnnotations(annotation.contributedArgsSchema);
|
|
31
50
|
}
|
|
32
|
-
for (const keyword of [
|
|
51
|
+
for (const keyword of [
|
|
52
|
+
"properties",
|
|
53
|
+
"patternProperties",
|
|
54
|
+
"$defs",
|
|
55
|
+
"definitions",
|
|
56
|
+
"dependentSchemas",
|
|
57
|
+
]) {
|
|
33
58
|
const schemas = schema[keyword];
|
|
34
|
-
if (isPlainObject(schemas))
|
|
59
|
+
if (isPlainObject(schemas))
|
|
60
|
+
for (const child of Object.values(schemas))
|
|
61
|
+
assertWorkflowReferenceAnnotations(child);
|
|
35
62
|
}
|
|
36
63
|
for (const keyword of ["allOf", "anyOf", "oneOf", "prefixItems"]) {
|
|
37
64
|
const schemas = schema[keyword];
|
|
38
|
-
if (Array.isArray(schemas))
|
|
65
|
+
if (Array.isArray(schemas))
|
|
66
|
+
for (const child of schemas) assertWorkflowReferenceAnnotations(child);
|
|
39
67
|
}
|
|
40
|
-
for (const keyword of [
|
|
68
|
+
for (const keyword of [
|
|
69
|
+
"additionalProperties",
|
|
70
|
+
"unevaluatedProperties",
|
|
71
|
+
"propertyNames",
|
|
72
|
+
"items",
|
|
73
|
+
"contains",
|
|
74
|
+
"not",
|
|
75
|
+
"if",
|
|
76
|
+
"then",
|
|
77
|
+
"else",
|
|
78
|
+
"unevaluatedItems",
|
|
79
|
+
"contentSchema",
|
|
80
|
+
]) {
|
|
41
81
|
assertWorkflowReferenceAnnotations(schema[keyword]);
|
|
42
82
|
}
|
|
43
83
|
}
|
|
44
84
|
|
|
45
|
-
export function assertWorkflowMetadata(
|
|
85
|
+
export function assertWorkflowMetadata(
|
|
86
|
+
workflow: NornAnyWorkflowDeclaration,
|
|
87
|
+
): void {
|
|
46
88
|
const { entrypoint } = workflow;
|
|
47
89
|
if (entrypoint === false) return;
|
|
48
|
-
if (!isPlainObject(entrypoint))
|
|
49
|
-
|
|
50
|
-
|
|
90
|
+
if (!isPlainObject(entrypoint))
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Workflow entrypoint must be false or an object with instructions: ${workflow.id}`,
|
|
93
|
+
);
|
|
94
|
+
if (
|
|
95
|
+
typeof entrypoint.instructions !== "string" ||
|
|
96
|
+
entrypoint.instructions.trim().length === 0
|
|
97
|
+
) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`Workflow entrypoint.instructions must be a nonempty string: ${workflow.id}`,
|
|
100
|
+
);
|
|
51
101
|
}
|
|
52
102
|
}
|
|
53
103
|
|
|
54
104
|
export function unwrapSchema(schema: TSchema): TSchema {
|
|
55
105
|
if (!Type.IsUnion(schema)) return schema;
|
|
56
|
-
const members = schema.anyOf.filter(member => !Type.IsNull(member));
|
|
106
|
+
const members = schema.anyOf.filter((member) => !Type.IsNull(member));
|
|
57
107
|
return members.length === 1 ? unwrapSchema(members[0]) : schema;
|
|
58
108
|
}
|
|
59
109
|
|
|
@@ -64,9 +114,13 @@ export function schemaShape(schema: TSchema): Record<string, TSchema> {
|
|
|
64
114
|
|
|
65
115
|
export function schemaType(schema: TSchema): string | undefined {
|
|
66
116
|
const unwrapped = unwrapSchema(schema);
|
|
67
|
-
return "type" in unwrapped && typeof unwrapped.type === "string"
|
|
117
|
+
return "type" in unwrapped && typeof unwrapped.type === "string"
|
|
118
|
+
? unwrapped.type
|
|
119
|
+
: undefined;
|
|
68
120
|
}
|
|
69
121
|
|
|
70
|
-
export function isPlainObject(
|
|
122
|
+
export function isPlainObject(
|
|
123
|
+
value: unknown,
|
|
124
|
+
): value is Record<string, unknown> {
|
|
71
125
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
72
126
|
}
|