@noetic-tools/core 0.0.1 → 0.1.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/README.md +31 -11
- package/dist/adapters/in-memory-fs-adapter.d.ts +1 -1
- package/dist/adapters/in-memory-fs-adapter.js +1 -1
- package/dist/adapters/in-memory-shell-adapter.d.ts +1 -1
- package/dist/adapters/in-memory-subprocess/manifest-persistence.d.ts +8 -0
- package/dist/adapters/in-memory-subprocess/manifest-persistence.js +56 -0
- package/dist/adapters/in-memory-subprocess/metadata.d.ts +12 -0
- package/dist/adapters/in-memory-subprocess/metadata.js +58 -0
- package/dist/adapters/in-memory-subprocess/step-completion.d.ts +3 -0
- package/dist/adapters/in-memory-subprocess/step-completion.js +86 -0
- package/dist/adapters/in-memory-subprocess/types.d.ts +88 -0
- package/dist/adapters/in-memory-subprocess/types.js +2 -0
- package/dist/adapters/in-memory-subprocess-adapter.d.ts +12 -4
- package/dist/adapters/in-memory-subprocess-adapter.js +164 -55
- package/dist/adapters/openrouter.d.ts +16 -7
- package/dist/adapters/openrouter.js +68 -7
- package/dist/builders/channel-builder.d.ts +1 -1
- package/dist/builders/control-flow-builders.d.ts +3 -3
- package/dist/builders/control-flow-builders.js +9 -4
- package/dist/builders/every.d.ts +3 -3
- package/dist/builders/every.js +5 -2
- package/dist/builders/layer-provides-builders.d.ts +1 -32
- package/dist/builders/layer-provides-builders.js +1 -33
- package/dist/builders/loop-builder.d.ts +2 -2
- package/dist/builders/loop-builder.js +5 -2
- package/dist/builders/memory-builder.d.ts +1 -1
- package/dist/builders/memory-builder.js +1 -1
- package/dist/builders/provide-builder.d.ts +2 -2
- package/dist/builders/provide-builder.js +5 -2
- package/dist/builders/spawn-builder.d.ts +22 -9
- package/dist/builders/spawn-builder.js +17 -3
- package/dist/builders/step-builders.d.ts +51 -30
- package/dist/builders/step-builders.js +31 -12
- package/dist/builders/tool-builder.d.ts +7 -3
- package/dist/builders/tool-builder.js +3 -1
- package/dist/builders/workflow-hydrator.d.ts +38 -0
- package/dist/builders/workflow-hydrator.js +336 -0
- package/dist/conditions/conditions.d.ts +4 -4
- package/dist/conditions/conditions.js +2 -2
- package/dist/errors/noetic-error.d.ts +1 -1
- package/dist/errors/noetic-error.js +2 -0
- package/dist/{runtime → harness}/agent-harness.d.ts +65 -45
- package/dist/harness/agent-harness.js +576 -0
- package/dist/harness/deps/adapters.d.ts +4 -0
- package/dist/harness/deps/adapters.js +4 -0
- package/dist/harness/deps/interpreter.d.ts +5 -0
- package/dist/harness/deps/interpreter.js +4 -0
- package/dist/harness/deps/memory.d.ts +5 -0
- package/dist/harness/deps/memory.js +4 -0
- package/dist/harness/deps/runtime.d.ts +10 -0
- package/dist/harness/deps/runtime.js +7 -0
- package/dist/harness/deps/types.d.ts +17 -0
- package/dist/harness/deps/types.js +1 -0
- package/dist/harness/model-call.d.ts +50 -0
- package/dist/harness/model-call.js +694 -0
- package/dist/harness/model-schema.d.ts +19 -0
- package/dist/harness/model-schema.js +46 -0
- package/dist/harness/step-bootstrap.d.ts +25 -0
- package/dist/harness/step-bootstrap.js +170 -0
- package/dist/index.d.ts +114 -76
- package/dist/index.js +74 -50
- package/dist/internal-test.d.ts +4 -4
- package/dist/internal-test.js +4 -4
- package/dist/interpreter/action-deps.d.ts +12 -0
- package/dist/interpreter/action-deps.js +10 -0
- package/dist/interpreter/action-types.d.ts +8 -0
- package/dist/interpreter/action-types.js +1 -0
- package/dist/interpreter/collect-tools.d.ts +2 -2
- package/dist/interpreter/collect-tools.js +6 -2
- package/dist/interpreter/execute-action.d.ts +22 -0
- package/dist/interpreter/execute-action.js +527 -0
- package/dist/interpreter/{execute-every.d.ts → execute-control.d.ts} +8 -2
- package/dist/interpreter/execute-control.js +530 -0
- package/dist/interpreter/execute.d.ts +16 -3
- package/dist/interpreter/execute.js +154 -51
- package/dist/interpreter/message-helpers.d.ts +1 -9
- package/dist/interpreter/message-helpers.js +1 -42
- package/dist/interpreter/step-dispatcher.d.ts +61 -0
- package/dist/interpreter/step-dispatcher.js +67 -0
- package/dist/interpreter/typeguards.d.ts +8 -15
- package/dist/interpreter/typeguards.js +4 -21
- package/dist/memory/budget.d.ts +2 -2
- package/dist/memory/budget.js +1 -1
- package/dist/{runtime → memory}/exec-context-factory.d.ts +2 -2
- package/dist/{runtime → memory}/exec-context-factory.js +1 -1
- package/dist/memory/flow-schema.d.ts +52 -0
- package/dist/memory/flow-schema.js +102 -0
- package/dist/memory/function-call-utils.d.ts +1 -1
- package/dist/memory/function-call-utils.js +4 -2
- package/dist/memory/layer-api.d.ts +4 -4
- package/dist/memory/layer-api.js +2 -2
- package/dist/memory/layer-lifecycle.d.ts +6 -6
- package/dist/memory/layer-lifecycle.js +6 -6
- package/dist/memory/layer-provides.d.ts +32 -0
- package/dist/memory/layer-provides.js +33 -0
- package/dist/memory/layer-usage.d.ts +4 -3
- package/dist/memory/layer-usage.js +9 -3
- package/dist/memory/layers/durable-task-state.d.ts +8 -8
- package/dist/memory/layers/durable-task-state.js +2 -2
- package/dist/memory/layers/file-reference.d.ts +1 -1
- package/dist/memory/layers/file-reference.js +303 -247
- package/dist/memory/layers/history-window.d.ts +1 -1
- package/dist/memory/layers/history-window.js +4 -4
- package/dist/memory/layers/observational-memory.d.ts +5 -5
- package/dist/memory/layers/observational-memory.js +2 -3
- package/dist/memory/layers/plan.d.ts +2 -2
- package/dist/memory/layers/plan.js +15 -10
- package/dist/memory/layers/static-content.d.ts +2 -2
- package/dist/memory/layers/static-content.js +1 -1
- package/dist/memory/layers/steering.d.ts +7 -7
- package/dist/memory/layers/steering.js +5 -5
- package/dist/memory/layers/tool-memory-layer.d.ts +2 -2
- package/dist/memory/layers/tool-memory-layer.js +1 -1
- package/dist/memory/layers/working-memory.d.ts +7 -7
- package/dist/memory/layers/working-memory.js +4 -4
- package/dist/memory/projector.d.ts +2 -2
- package/dist/memory/scope.d.ts +1 -1
- package/dist/memory/strip-unresolved.d.ts +1 -1
- package/dist/observability/span-impl.d.ts +1 -1
- package/dist/observability/trace-exporter.d.ts +2 -2
- package/dist/observability/trace-exporter.js +1 -1
- package/dist/patterns/dynamic-workflow.d.ts +55 -0
- package/dist/patterns/dynamic-workflow.js +194 -0
- package/dist/patterns/flow.d.ts +2 -52
- package/dist/patterns/flow.js +1 -103
- package/dist/patterns/interview.d.ts +2 -2
- package/dist/patterns/interview.js +5 -5
- package/dist/patterns/plans.d.ts +6 -6
- package/dist/patterns/plans.js +4 -4
- package/dist/patterns/ralph-wiggum.d.ts +4 -4
- package/dist/patterns/ralph-wiggum.js +5 -5
- package/dist/patterns/react.d.ts +3 -3
- package/dist/patterns/react.js +5 -5
- package/dist/portable/adapters.d.ts +6 -0
- package/dist/portable/adapters.js +6 -0
- package/dist/portable/ask-user.d.ts +4 -0
- package/dist/portable/ask-user.js +2 -0
- package/dist/portable/builders.d.ts +12 -0
- package/dist/portable/builders.js +12 -0
- package/dist/portable/memory-layers.d.ts +12 -0
- package/dist/portable/memory-layers.js +12 -0
- package/dist/portable/runtime.d.ts +4 -0
- package/dist/portable/runtime.js +4 -0
- package/dist/portable/until.d.ts +4 -0
- package/dist/portable/until.js +4 -0
- package/dist/portable.d.ts +8 -26
- package/dist/portable.js +8 -34
- package/dist/runtime/broadcaster-utils.d.ts +7 -3
- package/dist/runtime/broadcaster-utils.js +11 -6
- package/dist/runtime/channel-store.d.ts +1 -1
- package/dist/runtime/channel-store.js +2 -2
- package/dist/runtime/context-deps.d.ts +4 -0
- package/dist/runtime/context-deps.js +2 -0
- package/dist/runtime/context-impl.d.ts +42 -12
- package/dist/runtime/context-impl.js +52 -5
- package/dist/runtime/context-type-deps.d.ts +14 -0
- package/dist/runtime/context-type-deps.js +1 -0
- package/dist/runtime/cwd-helpers.d.ts +1 -1
- package/dist/runtime/detached-handle.d.ts +52 -4
- package/dist/runtime/detached-handle.js +218 -14
- package/dist/runtime/durable/checkpoint-store.d.ts +38 -0
- package/dist/runtime/durable/checkpoint-store.js +101 -0
- package/dist/runtime/durable/detached-signal.d.ts +37 -0
- package/dist/runtime/durable/detached-signal.js +52 -0
- package/dist/runtime/durable/harness-checkpoints.d.ts +51 -0
- package/dist/runtime/durable/harness-checkpoints.js +104 -0
- package/dist/runtime/durable/index.d.ts +10 -0
- package/dist/runtime/durable/index.js +5 -0
- package/dist/runtime/durable/runnable-loop.d.ts +100 -0
- package/dist/runtime/durable/runnable-loop.js +90 -0
- package/dist/runtime/durable/session-seed.d.ts +28 -0
- package/dist/runtime/durable/session-seed.js +27 -0
- package/dist/runtime/durable/stall-nudge.d.ts +82 -0
- package/dist/runtime/durable/stall-nudge.js +87 -0
- package/dist/runtime/event-broadcaster.d.ts +1 -1
- package/dist/runtime/in-memory-storage.d.ts +1 -1
- package/dist/runtime/in-memory-storage.js +1 -1
- package/dist/runtime/item-log-impl.d.ts +3 -3
- package/dist/runtime/item-log-impl.js +1 -1
- package/dist/runtime/message-queue.d.ts +2 -2
- package/dist/runtime/session-runner.d.ts +7 -7
- package/dist/runtime/session-runner.js +3 -3
- package/dist/runtime/session-streams.d.ts +3 -3
- package/dist/runtime/session-streams.js +1 -1
- package/dist/runtime/step-registry.d.ts +42 -0
- package/dist/runtime/step-registry.js +77 -0
- package/dist/runtime/tool-memory.d.ts +3 -3
- package/dist/schemas/item.d.ts +1 -1
- package/dist/schemas/workflow.d.ts +139 -0
- package/dist/schemas/workflow.js +232 -0
- package/dist/types/ask-user-types.d.ts +57 -0
- package/dist/types/ask-user-types.js +74 -0
- package/dist/types/checkpoint.d.ts +98 -0
- package/dist/types/checkpoint.js +81 -0
- package/dist/types/common.d.ts +1 -50
- package/dist/types/context-parts/item-log.d.ts +6 -0
- package/dist/types/context-parts/item-log.js +1 -0
- package/dist/types/context-parts/layer-usage.d.ts +18 -0
- package/dist/types/context-parts/layer-usage.js +1 -0
- package/dist/types/context.d.ts +140 -31
- package/dist/types/error.d.ts +15 -0
- package/dist/types/harness-result.d.ts +2 -2
- package/dist/types/items.d.ts +18 -2
- package/dist/types/memory-context.d.ts +39 -0
- package/dist/types/memory-context.js +1 -0
- package/dist/types/memory.d.ts +38 -68
- package/dist/types/mutable-context.d.ts +3 -3
- package/dist/types/runtime.d.ts +14 -13
- package/dist/types/steering.d.ts +2 -2
- package/dist/types/step-registrar.d.ts +46 -0
- package/dist/types/step-registrar.js +56 -0
- package/dist/types/step.d.ts +34 -9
- package/dist/types/subprocess-adapter.d.ts +119 -3
- package/dist/types/subprocess-adapter.js +2 -0
- package/dist/types/tool-context.d.ts +6 -6
- package/dist/types/tool.d.ts +64 -0
- package/dist/types/tool.js +1 -0
- package/dist/unstable.d.ts +9 -9
- package/dist/unstable.js +7 -7
- package/dist/until/combinators.d.ts +1 -1
- package/dist/until/never.d.ts +1 -1
- package/dist/until/predicates.d.ts +13 -4
- package/dist/until/predicates.js +16 -2
- package/dist/util/message-helpers.d.ts +17 -0
- package/dist/util/message-helpers.js +64 -0
- package/package.json +6 -4
- package/dist/adapters/local-fs-adapter.d.ts +0 -3
- package/dist/adapters/local-fs-adapter.js +0 -43
- package/dist/adapters/local-shell-adapter.d.ts +0 -51
- package/dist/adapters/local-shell-adapter.js +0 -167
- package/dist/adapters/local-subprocess-adapter.d.ts +0 -16
- package/dist/adapters/local-subprocess-adapter.js +0 -187
- package/dist/conditions/index.d.ts +0 -3
- package/dist/conditions/index.js +0 -2
- package/dist/interpreter/execute-branch.d.ts +0 -3
- package/dist/interpreter/execute-branch.js +0 -10
- package/dist/interpreter/execute-every.js +0 -143
- package/dist/interpreter/execute-fork.d.ts +0 -3
- package/dist/interpreter/execute-fork.js +0 -215
- package/dist/interpreter/execute-llm.d.ts +0 -4
- package/dist/interpreter/execute-llm.js +0 -217
- package/dist/interpreter/execute-loop.d.ts +0 -3
- package/dist/interpreter/execute-loop.js +0 -171
- package/dist/interpreter/execute-provide.d.ts +0 -10
- package/dist/interpreter/execute-provide.js +0 -64
- package/dist/interpreter/execute-run.d.ts +0 -3
- package/dist/interpreter/execute-run.js +0 -39
- package/dist/interpreter/execute-spawn.d.ts +0 -11
- package/dist/interpreter/execute-spawn.js +0 -113
- package/dist/interpreter/execute-tool.d.ts +0 -5
- package/dist/interpreter/execute-tool.js +0 -81
- package/dist/runtime/agent-harness.js +0 -1170
- /package/dist/{interpreter → util}/framework-cast.d.ts +0 -0
- /package/dist/{interpreter → util}/framework-cast.js +0 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ContextMemory } from '../types/memory.js';
|
|
2
|
+
import type { Step } from '../types/step.js';
|
|
3
|
+
/** Registry-wide step type — stored at the widest generic parameters so
|
|
4
|
+
* callers can register steps with narrower input/output types without
|
|
5
|
+
* fighting variance. The public `Step` default already uses `unknown` for
|
|
6
|
+
* the input and output parameters, matching this shape. */
|
|
7
|
+
type RegisteredStep = Step<ContextMemory, unknown, unknown>;
|
|
8
|
+
/**
|
|
9
|
+
* @public
|
|
10
|
+
* Registers a step so the subprocess adapter can look it up by id.
|
|
11
|
+
*
|
|
12
|
+
* Called automatically by the step builders when a `Step` is constructed.
|
|
13
|
+
* Policy: **latest registration wins**. Dispatch-and-lookup happen in the
|
|
14
|
+
* same tick, so the live entry is always the one the caller just built;
|
|
15
|
+
* cross-test pollution from bun's per-file process model (describe blocks
|
|
16
|
+
* rebuild the same step id) is not a safety concern here. Strict
|
|
17
|
+
* "reject duplicate id with a different body" detection + a test-side
|
|
18
|
+
* `clearRegistry` wiring is deferred — see the tracked follow-up task on
|
|
19
|
+
* the team's board (strict-registry-plus-test-clear).
|
|
20
|
+
*/
|
|
21
|
+
export declare function registerStep<TMemory, I, O>(step: Step<TMemory, I, O>): void;
|
|
22
|
+
/**
|
|
23
|
+
* @public
|
|
24
|
+
* Looks up a registered step by id. Returns `null` when the id is not known
|
|
25
|
+
* — callers (e.g. the in-memory adapter's step dispatch path) translate the
|
|
26
|
+
* miss into a typed configuration error.
|
|
27
|
+
*/
|
|
28
|
+
export declare function lookupStep(id: string): RegisteredStep | null;
|
|
29
|
+
/**
|
|
30
|
+
* @public
|
|
31
|
+
* Returns a read-only view over the registry. Primarily for tests and
|
|
32
|
+
* debugging; production callers should use `lookupStep`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getRegistry(): ReadonlyMap<string, RegisteredStep>;
|
|
35
|
+
/**
|
|
36
|
+
* @public
|
|
37
|
+
* Clears the registry. Test-only helper — exported because several suites
|
|
38
|
+
* need a clean registry between describe blocks. Not part of the public API
|
|
39
|
+
* surface consumed by agent authors.
|
|
40
|
+
*/
|
|
41
|
+
export declare function clearRegistry(): void;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { NoeticConfigError } from '../errors/noetic-config-error.js';
|
|
2
|
+
import { setDefaultRegistrar } from '../types/step-registrar.js';
|
|
3
|
+
import { frameworkCast } from '../util/framework-cast.js';
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region Module state
|
|
6
|
+
const registry = new Map();
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region Public API
|
|
9
|
+
/**
|
|
10
|
+
* @public
|
|
11
|
+
* Registers a step so the subprocess adapter can look it up by id.
|
|
12
|
+
*
|
|
13
|
+
* Called automatically by the step builders when a `Step` is constructed.
|
|
14
|
+
* Policy: **latest registration wins**. Dispatch-and-lookup happen in the
|
|
15
|
+
* same tick, so the live entry is always the one the caller just built;
|
|
16
|
+
* cross-test pollution from bun's per-file process model (describe blocks
|
|
17
|
+
* rebuild the same step id) is not a safety concern here. Strict
|
|
18
|
+
* "reject duplicate id with a different body" detection + a test-side
|
|
19
|
+
* `clearRegistry` wiring is deferred — see the tracked follow-up task on
|
|
20
|
+
* the team's board (strict-registry-plus-test-clear).
|
|
21
|
+
*/
|
|
22
|
+
export function registerStep(step) {
|
|
23
|
+
if (!step.id || step.id.trim() === '') {
|
|
24
|
+
throw new NoeticConfigError({
|
|
25
|
+
code: 'EMPTY_STEP_ID',
|
|
26
|
+
message: 'registerStep() requires a step with a non-empty id.',
|
|
27
|
+
hint: 'Set `id` on the step before constructing it.',
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
// `frameworkCast` is the approved single-point escape for generic variance:
|
|
31
|
+
// narrowing I/O from specific types to the registry's widened `unknown`
|
|
32
|
+
// shape is structurally safe at runtime because the registry only holds
|
|
33
|
+
// references and dispatches them through the same `execute()` pipeline.
|
|
34
|
+
const widened = frameworkCast(step);
|
|
35
|
+
registry.set(step.id, widened);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* @public
|
|
39
|
+
* Looks up a registered step by id. Returns `null` when the id is not known
|
|
40
|
+
* — callers (e.g. the in-memory adapter's step dispatch path) translate the
|
|
41
|
+
* miss into a typed configuration error.
|
|
42
|
+
*/
|
|
43
|
+
export function lookupStep(id) {
|
|
44
|
+
return registry.get(id) ?? null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* @public
|
|
48
|
+
* Returns a read-only view over the registry. Primarily for tests and
|
|
49
|
+
* debugging; production callers should use `lookupStep`.
|
|
50
|
+
*/
|
|
51
|
+
export function getRegistry() {
|
|
52
|
+
return registry;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* @public
|
|
56
|
+
* Clears the registry. Test-only helper — exported because several suites
|
|
57
|
+
* need a clean registry between describe blocks. Not part of the public API
|
|
58
|
+
* surface consumed by agent authors.
|
|
59
|
+
*/
|
|
60
|
+
export function clearRegistry() {
|
|
61
|
+
registry.clear();
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region Default-registrar installation
|
|
65
|
+
/**
|
|
66
|
+
* Install this module's `registerStep` as the runtime default registrar.
|
|
67
|
+
* Executes on first import — which happens transitively from
|
|
68
|
+
* `agent-harness.ts` and from anywhere that imports `@noetic-tools/core`'s
|
|
69
|
+
* top-level barrel. Builders call `getDefaultRegistrar().register(step)`
|
|
70
|
+
* from `../types/step-registrar` and get this concrete implementation
|
|
71
|
+
* without depending on `core-runtime` themselves (fixes the
|
|
72
|
+
* `core-primitives → core-runtime` layer_direction violations).
|
|
73
|
+
*/
|
|
74
|
+
setDefaultRegistrar({
|
|
75
|
+
register: registerStep,
|
|
76
|
+
});
|
|
77
|
+
//#endregion
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TurnContext } from '@openrouter/agent';
|
|
2
|
-
import type { Context } from '../types/context';
|
|
3
|
-
import type { AgentHarnessContract } from '../types/runtime';
|
|
4
|
-
import type { ToolExecutionContext, ToolMemory } from '../types/tool-context';
|
|
2
|
+
import type { Context } from '../types/context.js';
|
|
3
|
+
import type { AgentHarnessContract } from '../types/runtime.js';
|
|
4
|
+
import type { ToolExecutionContext, ToolMemory } from '../types/tool-context.js';
|
|
5
5
|
export declare function buildToolMemory(harness: AgentHarnessContract, ctx: Context): ToolMemory;
|
|
6
6
|
export declare function buildToolExecutionContext(ctx: Context, harness: AgentHarnessContract, turnContext?: TurnContext): ToolExecutionContext;
|
package/dist/schemas/item.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* don't need to re-validate every provider field TypeScript already types.
|
|
14
14
|
*/
|
|
15
15
|
import { z } from 'zod';
|
|
16
|
-
import type { Item, ItemSchemaExtensions } from '../types/items';
|
|
16
|
+
import type { Item, ItemSchemaExtensions } from '../types/items.js';
|
|
17
17
|
/** @public Structural validator for `Item`. Asserts non-empty string `type` discriminant. */
|
|
18
18
|
export declare const ItemSchema: z.ZodCustom<Item, Item>;
|
|
19
19
|
type ItemSchemaCategory = keyof Required<ItemSchemaExtensions>;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for JSON-serialisable workflow definitions.
|
|
3
|
+
*
|
|
4
|
+
* A `WorkflowDocument` is a portable, JSON-safe representation of a noetic
|
|
5
|
+
* step tree. It covers every step kind except `run` (which carries arbitrary
|
|
6
|
+
* closures). The hydrator in `builders/workflow-hydrator.ts` converts a
|
|
7
|
+
* validated document back into live `Step` objects via the existing builders.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
interface UntilAnyPredicate {
|
|
11
|
+
kind: 'any';
|
|
12
|
+
predicates: UntilPredicate[];
|
|
13
|
+
}
|
|
14
|
+
interface UntilAllPredicate {
|
|
15
|
+
kind: 'all';
|
|
16
|
+
predicates: UntilPredicate[];
|
|
17
|
+
}
|
|
18
|
+
/** @public Discriminated union of named until predicates usable in JSON workflows. */
|
|
19
|
+
export type UntilPredicate = {
|
|
20
|
+
kind: 'maxSteps';
|
|
21
|
+
n: number;
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'maxCost';
|
|
24
|
+
usd: number;
|
|
25
|
+
} | {
|
|
26
|
+
kind: 'maxDuration';
|
|
27
|
+
ms: number;
|
|
28
|
+
} | {
|
|
29
|
+
kind: 'noToolCalls';
|
|
30
|
+
} | {
|
|
31
|
+
kind: 'outputContains';
|
|
32
|
+
marker: string;
|
|
33
|
+
} | {
|
|
34
|
+
kind: 'outputEquals';
|
|
35
|
+
sentinel: string;
|
|
36
|
+
} | {
|
|
37
|
+
kind: 'converged';
|
|
38
|
+
threshold?: number;
|
|
39
|
+
} | UntilAnyPredicate | UntilAllPredicate;
|
|
40
|
+
/** @public Zod schema validating a named `until` predicate (including `any`/`all` combinators). */
|
|
41
|
+
export declare const UntilPredicateSchema: z.ZodType<UntilPredicate>;
|
|
42
|
+
/** @public ESM literal enum for merge strategies. */
|
|
43
|
+
export declare const MergeStrategy: {
|
|
44
|
+
readonly Last: "last";
|
|
45
|
+
readonly First: "first";
|
|
46
|
+
readonly Concat: "concat";
|
|
47
|
+
};
|
|
48
|
+
/** @public Named merge strategy for fork nodes. */
|
|
49
|
+
export type MergeStrategy = (typeof MergeStrategy)[keyof typeof MergeStrategy];
|
|
50
|
+
/** @public Zod schema for the named merge strategy used by `fork` nodes. */
|
|
51
|
+
export declare const MergeStrategySchema: z.ZodEnum<{
|
|
52
|
+
concat: "concat";
|
|
53
|
+
last: "last";
|
|
54
|
+
first: "first";
|
|
55
|
+
}>;
|
|
56
|
+
declare const ModelParamsSchema: z.ZodObject<{
|
|
57
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
58
|
+
topP: z.ZodOptional<z.ZodNumber>;
|
|
59
|
+
maxTokens: z.ZodOptional<z.ZodNumber>;
|
|
60
|
+
stopSequences: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
interface WorkflowNodeBase {
|
|
63
|
+
id: string;
|
|
64
|
+
}
|
|
65
|
+
export interface LlmWorkflowNode extends WorkflowNodeBase {
|
|
66
|
+
kind: 'llm';
|
|
67
|
+
model?: string;
|
|
68
|
+
instructions: string;
|
|
69
|
+
tools?: string[];
|
|
70
|
+
params?: z.infer<typeof ModelParamsSchema>;
|
|
71
|
+
}
|
|
72
|
+
export interface ToolWorkflowNode extends WorkflowNodeBase {
|
|
73
|
+
kind: 'tool';
|
|
74
|
+
toolName: string;
|
|
75
|
+
args?: Record<string, unknown>;
|
|
76
|
+
}
|
|
77
|
+
export interface BranchRoute {
|
|
78
|
+
match: string;
|
|
79
|
+
target: WorkflowNode;
|
|
80
|
+
}
|
|
81
|
+
export interface BranchWorkflowNode extends WorkflowNodeBase {
|
|
82
|
+
kind: 'branch';
|
|
83
|
+
routes: BranchRoute[];
|
|
84
|
+
default?: WorkflowNode;
|
|
85
|
+
}
|
|
86
|
+
export interface ForkWorkflowNode extends WorkflowNodeBase {
|
|
87
|
+
kind: 'fork';
|
|
88
|
+
mode: 'race' | 'all' | 'settle';
|
|
89
|
+
paths: WorkflowNode[];
|
|
90
|
+
merge?: MergeStrategy;
|
|
91
|
+
concurrency?: number;
|
|
92
|
+
}
|
|
93
|
+
export interface SpawnWorkflowNode extends WorkflowNodeBase {
|
|
94
|
+
kind: 'spawn';
|
|
95
|
+
child: WorkflowNode;
|
|
96
|
+
timeout?: number;
|
|
97
|
+
}
|
|
98
|
+
export interface ProvideWorkflowNode extends WorkflowNodeBase {
|
|
99
|
+
kind: 'provide';
|
|
100
|
+
child: WorkflowNode;
|
|
101
|
+
layers: string[];
|
|
102
|
+
}
|
|
103
|
+
export interface LoopWorkflowNode extends WorkflowNodeBase {
|
|
104
|
+
kind: 'loop';
|
|
105
|
+
body: WorkflowNode;
|
|
106
|
+
until: UntilPredicate;
|
|
107
|
+
maxIterations?: number;
|
|
108
|
+
}
|
|
109
|
+
export interface SequenceWorkflowNode extends WorkflowNodeBase {
|
|
110
|
+
kind: 'sequence';
|
|
111
|
+
steps: WorkflowNode[];
|
|
112
|
+
}
|
|
113
|
+
export interface EveryWorkflowNode extends WorkflowNodeBase {
|
|
114
|
+
kind: 'every';
|
|
115
|
+
step: WorkflowNode;
|
|
116
|
+
ms: number;
|
|
117
|
+
onError?: 'continue' | 'fail';
|
|
118
|
+
}
|
|
119
|
+
/** @public Discriminated union of all JSON-serialisable workflow node kinds. */
|
|
120
|
+
export type WorkflowNode = LlmWorkflowNode | ToolWorkflowNode | BranchWorkflowNode | ForkWorkflowNode | SpawnWorkflowNode | ProvideWorkflowNode | LoopWorkflowNode | SequenceWorkflowNode | EveryWorkflowNode;
|
|
121
|
+
/** @public Zod schema validating a single `WorkflowNode` (any of the 9 JSON-safe kinds). */
|
|
122
|
+
export declare const WorkflowNodeSchema: z.ZodType<WorkflowNode>;
|
|
123
|
+
/** @public Top-level envelope for a JSON workflow definition. */
|
|
124
|
+
export interface WorkflowDocument {
|
|
125
|
+
version: 1;
|
|
126
|
+
root: WorkflowNode;
|
|
127
|
+
}
|
|
128
|
+
/** @public Zod schema validating a complete `WorkflowDocument`. */
|
|
129
|
+
export declare const WorkflowDocumentSchema: z.ZodType<WorkflowDocument>;
|
|
130
|
+
/** Validates a candidate workflow document. Throws `ZodError` on invalid input. */
|
|
131
|
+
export declare function validateWorkflow(input: unknown): WorkflowDocument;
|
|
132
|
+
/** Walks a workflow tree depth-first, yielding each node. */
|
|
133
|
+
export declare function walkWorkflow(node: WorkflowNode): Iterable<WorkflowNode>;
|
|
134
|
+
/**
|
|
135
|
+
* Returns the maximum depth of a workflow tree.
|
|
136
|
+
* Leaf nodes (`llm`, `tool`) have depth 0. Structural nodes add +1.
|
|
137
|
+
*/
|
|
138
|
+
export declare function workflowDepth(node: WorkflowNode): number;
|
|
139
|
+
export {};
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for JSON-serialisable workflow definitions.
|
|
3
|
+
*
|
|
4
|
+
* A `WorkflowDocument` is a portable, JSON-safe representation of a noetic
|
|
5
|
+
* step tree. It covers every step kind except `run` (which carries arbitrary
|
|
6
|
+
* closures). The hydrator in `builders/workflow-hydrator.ts` converts a
|
|
7
|
+
* validated document back into live `Step` objects via the existing builders.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region Until Predicate Schemas
|
|
12
|
+
const MaxStepsPredicateSchema = z.object({
|
|
13
|
+
kind: z.literal('maxSteps'),
|
|
14
|
+
n: z.number().int().positive(),
|
|
15
|
+
});
|
|
16
|
+
const MaxCostPredicateSchema = z.object({
|
|
17
|
+
kind: z.literal('maxCost'),
|
|
18
|
+
usd: z.number().positive(),
|
|
19
|
+
});
|
|
20
|
+
const MaxDurationPredicateSchema = z.object({
|
|
21
|
+
kind: z.literal('maxDuration'),
|
|
22
|
+
ms: z.number().positive(),
|
|
23
|
+
});
|
|
24
|
+
const NoToolCallsPredicateSchema = z.object({
|
|
25
|
+
kind: z.literal('noToolCalls'),
|
|
26
|
+
});
|
|
27
|
+
const OutputContainsPredicateSchema = z.object({
|
|
28
|
+
kind: z.literal('outputContains'),
|
|
29
|
+
marker: z.string().min(1),
|
|
30
|
+
});
|
|
31
|
+
const OutputEqualsPredicateSchema = z.object({
|
|
32
|
+
kind: z.literal('outputEquals'),
|
|
33
|
+
sentinel: z.string().min(1),
|
|
34
|
+
});
|
|
35
|
+
const ConvergedPredicateSchema = z.object({
|
|
36
|
+
kind: z.literal('converged'),
|
|
37
|
+
threshold: z.number().min(0).max(1).optional(),
|
|
38
|
+
});
|
|
39
|
+
const UntilPredicateRef = z.lazy(() => UntilPredicateSchema);
|
|
40
|
+
const AnyPredicateSchema = z.object({
|
|
41
|
+
kind: z.literal('any'),
|
|
42
|
+
predicates: z.array(UntilPredicateRef).min(1),
|
|
43
|
+
});
|
|
44
|
+
const AllPredicateSchema = z.object({
|
|
45
|
+
kind: z.literal('all'),
|
|
46
|
+
predicates: z.array(UntilPredicateRef).min(1),
|
|
47
|
+
});
|
|
48
|
+
/** @public Zod schema validating a named `until` predicate (including `any`/`all` combinators). */
|
|
49
|
+
export const UntilPredicateSchema = z.union([
|
|
50
|
+
MaxStepsPredicateSchema,
|
|
51
|
+
MaxCostPredicateSchema,
|
|
52
|
+
MaxDurationPredicateSchema,
|
|
53
|
+
NoToolCallsPredicateSchema,
|
|
54
|
+
OutputContainsPredicateSchema,
|
|
55
|
+
OutputEqualsPredicateSchema,
|
|
56
|
+
ConvergedPredicateSchema,
|
|
57
|
+
AnyPredicateSchema,
|
|
58
|
+
AllPredicateSchema,
|
|
59
|
+
]);
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region Merge Strategy
|
|
62
|
+
/** @public ESM literal enum for merge strategies. */
|
|
63
|
+
export const MergeStrategy = {
|
|
64
|
+
Last: 'last',
|
|
65
|
+
First: 'first',
|
|
66
|
+
Concat: 'concat',
|
|
67
|
+
};
|
|
68
|
+
/** @public Zod schema for the named merge strategy used by `fork` nodes. */
|
|
69
|
+
export const MergeStrategySchema = z.enum([
|
|
70
|
+
'last',
|
|
71
|
+
'first',
|
|
72
|
+
'concat',
|
|
73
|
+
]);
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region Model Params
|
|
76
|
+
const ModelParamsSchema = z.object({
|
|
77
|
+
temperature: z.number().min(0).optional(),
|
|
78
|
+
topP: z.number().min(0).max(1).optional(),
|
|
79
|
+
maxTokens: z.number().int().positive().optional(),
|
|
80
|
+
stopSequences: z.array(z.string()).optional(),
|
|
81
|
+
});
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region Workflow Node Schema
|
|
84
|
+
const WorkflowNodeRef = z.lazy(() => WorkflowNodeSchema);
|
|
85
|
+
const SHARED_FIELDS = {
|
|
86
|
+
id: z.string().min(1),
|
|
87
|
+
};
|
|
88
|
+
const LlmNodeSchema = z.object({
|
|
89
|
+
kind: z.literal('llm'),
|
|
90
|
+
...SHARED_FIELDS,
|
|
91
|
+
model: z.string().optional(),
|
|
92
|
+
instructions: z.string(),
|
|
93
|
+
tools: z.array(z.string()).optional(),
|
|
94
|
+
params: ModelParamsSchema.optional(),
|
|
95
|
+
});
|
|
96
|
+
const ToolNodeSchema = z.object({
|
|
97
|
+
kind: z.literal('tool'),
|
|
98
|
+
...SHARED_FIELDS,
|
|
99
|
+
toolName: z.string().min(1),
|
|
100
|
+
args: z.record(z.string(), z.unknown()).optional(),
|
|
101
|
+
});
|
|
102
|
+
const BranchRouteSchema = z.object({
|
|
103
|
+
match: z.string().min(1),
|
|
104
|
+
target: z.lazy(() => WorkflowNodeSchema),
|
|
105
|
+
});
|
|
106
|
+
const BranchNodeSchema = z.object({
|
|
107
|
+
kind: z.literal('branch'),
|
|
108
|
+
...SHARED_FIELDS,
|
|
109
|
+
routes: z.array(BranchRouteSchema).min(1),
|
|
110
|
+
default: WorkflowNodeRef.optional(),
|
|
111
|
+
});
|
|
112
|
+
const ForkNodeSchema = z.object({
|
|
113
|
+
kind: z.literal('fork'),
|
|
114
|
+
...SHARED_FIELDS,
|
|
115
|
+
mode: z.enum([
|
|
116
|
+
'race',
|
|
117
|
+
'all',
|
|
118
|
+
'settle',
|
|
119
|
+
]),
|
|
120
|
+
paths: z.array(WorkflowNodeRef).min(1),
|
|
121
|
+
merge: MergeStrategySchema.optional(),
|
|
122
|
+
concurrency: z.number().int().positive().optional(),
|
|
123
|
+
});
|
|
124
|
+
const SpawnNodeSchema = z.object({
|
|
125
|
+
kind: z.literal('spawn'),
|
|
126
|
+
...SHARED_FIELDS,
|
|
127
|
+
child: WorkflowNodeRef,
|
|
128
|
+
timeout: z.number().positive().optional(),
|
|
129
|
+
});
|
|
130
|
+
const ProvideNodeSchema = z.object({
|
|
131
|
+
kind: z.literal('provide'),
|
|
132
|
+
...SHARED_FIELDS,
|
|
133
|
+
child: WorkflowNodeRef,
|
|
134
|
+
layers: z.array(z.string().min(1)).min(1),
|
|
135
|
+
});
|
|
136
|
+
const LoopNodeSchema = z.object({
|
|
137
|
+
kind: z.literal('loop'),
|
|
138
|
+
...SHARED_FIELDS,
|
|
139
|
+
body: WorkflowNodeRef,
|
|
140
|
+
until: UntilPredicateSchema,
|
|
141
|
+
maxIterations: z.number().int().positive().optional(),
|
|
142
|
+
});
|
|
143
|
+
const SequenceNodeSchema = z.object({
|
|
144
|
+
kind: z.literal('sequence'),
|
|
145
|
+
...SHARED_FIELDS,
|
|
146
|
+
steps: z.array(WorkflowNodeRef).min(1),
|
|
147
|
+
});
|
|
148
|
+
const EveryNodeSchema = z.object({
|
|
149
|
+
kind: z.literal('every'),
|
|
150
|
+
...SHARED_FIELDS,
|
|
151
|
+
step: WorkflowNodeRef,
|
|
152
|
+
ms: z.number().nonnegative(),
|
|
153
|
+
onError: z
|
|
154
|
+
.enum([
|
|
155
|
+
'continue',
|
|
156
|
+
'fail',
|
|
157
|
+
])
|
|
158
|
+
.optional(),
|
|
159
|
+
});
|
|
160
|
+
/** @public Zod schema validating a single `WorkflowNode` (any of the 9 JSON-safe kinds). */
|
|
161
|
+
export const WorkflowNodeSchema = z.discriminatedUnion('kind', [
|
|
162
|
+
LlmNodeSchema,
|
|
163
|
+
ToolNodeSchema,
|
|
164
|
+
BranchNodeSchema,
|
|
165
|
+
ForkNodeSchema,
|
|
166
|
+
SpawnNodeSchema,
|
|
167
|
+
ProvideNodeSchema,
|
|
168
|
+
LoopNodeSchema,
|
|
169
|
+
SequenceNodeSchema,
|
|
170
|
+
EveryNodeSchema,
|
|
171
|
+
]);
|
|
172
|
+
/** @public Zod schema validating a complete `WorkflowDocument`. */
|
|
173
|
+
export const WorkflowDocumentSchema = z.object({
|
|
174
|
+
version: z.literal(1),
|
|
175
|
+
root: WorkflowNodeSchema,
|
|
176
|
+
});
|
|
177
|
+
//#endregion
|
|
178
|
+
//#region Helpers
|
|
179
|
+
/** Returns the direct child nodes of a workflow node. Leaf nodes return an empty array. */
|
|
180
|
+
function childNodes(node) {
|
|
181
|
+
switch (node.kind) {
|
|
182
|
+
case 'sequence':
|
|
183
|
+
return node.steps;
|
|
184
|
+
case 'fork':
|
|
185
|
+
return node.paths;
|
|
186
|
+
case 'spawn':
|
|
187
|
+
case 'provide':
|
|
188
|
+
return [
|
|
189
|
+
node.child,
|
|
190
|
+
];
|
|
191
|
+
case 'loop':
|
|
192
|
+
return [
|
|
193
|
+
node.body,
|
|
194
|
+
];
|
|
195
|
+
case 'every':
|
|
196
|
+
return [
|
|
197
|
+
node.step,
|
|
198
|
+
];
|
|
199
|
+
case 'branch': {
|
|
200
|
+
const children = node.routes.map((r) => r.target);
|
|
201
|
+
if (node.default) {
|
|
202
|
+
children.push(node.default);
|
|
203
|
+
}
|
|
204
|
+
return children;
|
|
205
|
+
}
|
|
206
|
+
default:
|
|
207
|
+
return [];
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/** Validates a candidate workflow document. Throws `ZodError` on invalid input. */
|
|
211
|
+
export function validateWorkflow(input) {
|
|
212
|
+
return WorkflowDocumentSchema.parse(input);
|
|
213
|
+
}
|
|
214
|
+
/** Walks a workflow tree depth-first, yielding each node. */
|
|
215
|
+
export function* walkWorkflow(node) {
|
|
216
|
+
yield node;
|
|
217
|
+
for (const child of childNodes(node)) {
|
|
218
|
+
yield* walkWorkflow(child);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Returns the maximum depth of a workflow tree.
|
|
223
|
+
* Leaf nodes (`llm`, `tool`) have depth 0. Structural nodes add +1.
|
|
224
|
+
*/
|
|
225
|
+
export function workflowDepth(node) {
|
|
226
|
+
const children = childNodes(node);
|
|
227
|
+
if (children.length === 0) {
|
|
228
|
+
return 0;
|
|
229
|
+
}
|
|
230
|
+
return 1 + Math.max(0, ...children.map(workflowDepth));
|
|
231
|
+
}
|
|
232
|
+
//#endregion
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire schemas + types for the ask-user pattern.
|
|
3
|
+
*
|
|
4
|
+
* The "ask-user" shape is a portable, tool-agnostic description of an
|
|
5
|
+
* interactive prompt (questions + options + answers) that any UI — in-process
|
|
6
|
+
* TUI modal, IPC-backed runner, future web renderer — can render and
|
|
7
|
+
* respond to. The schemas live in core so callers on either side of an
|
|
8
|
+
* adapter (tool author, TUI, IPC protocol) validate against the same
|
|
9
|
+
* definitions rather than each package maintaining a drift-prone copy.
|
|
10
|
+
*
|
|
11
|
+
* Kept separate from a concrete tool factory so the TUI can import the
|
|
12
|
+
* types without pulling in a tool that closes over an `AskUserService`.
|
|
13
|
+
*/
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
export declare const AskUserOptionSchema: z.ZodObject<{
|
|
16
|
+
label: z.ZodString;
|
|
17
|
+
description: z.ZodString;
|
|
18
|
+
preview: z.ZodOptional<z.ZodString>;
|
|
19
|
+
}, z.core.$strip>;
|
|
20
|
+
export declare const AskUserQuestionSchema: z.ZodObject<{
|
|
21
|
+
question: z.ZodString;
|
|
22
|
+
header: z.ZodString;
|
|
23
|
+
options: z.ZodArray<z.ZodObject<{
|
|
24
|
+
label: z.ZodString;
|
|
25
|
+
description: z.ZodString;
|
|
26
|
+
preview: z.ZodOptional<z.ZodString>;
|
|
27
|
+
}, z.core.$strip>>;
|
|
28
|
+
multiSelect: z.ZodDefault<z.ZodBoolean>;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
export declare const AskUserInputSchema: z.ZodObject<{
|
|
31
|
+
questions: z.ZodArray<z.ZodObject<{
|
|
32
|
+
question: z.ZodString;
|
|
33
|
+
header: z.ZodString;
|
|
34
|
+
options: z.ZodArray<z.ZodObject<{
|
|
35
|
+
label: z.ZodString;
|
|
36
|
+
description: z.ZodString;
|
|
37
|
+
preview: z.ZodOptional<z.ZodString>;
|
|
38
|
+
}, z.core.$strip>>;
|
|
39
|
+
multiSelect: z.ZodDefault<z.ZodBoolean>;
|
|
40
|
+
}, z.core.$strip>>;
|
|
41
|
+
}, z.core.$strip>;
|
|
42
|
+
export declare const AskUserAnnotationSchema: z.ZodObject<{
|
|
43
|
+
notes: z.ZodOptional<z.ZodString>;
|
|
44
|
+
preview: z.ZodOptional<z.ZodString>;
|
|
45
|
+
}, z.core.$strip>;
|
|
46
|
+
export declare const AskUserOutputSchema: z.ZodObject<{
|
|
47
|
+
answers: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
48
|
+
annotations: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
49
|
+
notes: z.ZodOptional<z.ZodString>;
|
|
50
|
+
preview: z.ZodOptional<z.ZodString>;
|
|
51
|
+
}, z.core.$strip>>>;
|
|
52
|
+
}, z.core.$strip>;
|
|
53
|
+
export type AskUserOption = z.infer<typeof AskUserOptionSchema>;
|
|
54
|
+
export type AskUserQuestion = z.infer<typeof AskUserQuestionSchema>;
|
|
55
|
+
export type AskUserInput = z.infer<typeof AskUserInputSchema>;
|
|
56
|
+
export type AskUserAnnotation = z.infer<typeof AskUserAnnotationSchema>;
|
|
57
|
+
export type AskUserOutput = z.infer<typeof AskUserOutputSchema>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire schemas + types for the ask-user pattern.
|
|
3
|
+
*
|
|
4
|
+
* The "ask-user" shape is a portable, tool-agnostic description of an
|
|
5
|
+
* interactive prompt (questions + options + answers) that any UI — in-process
|
|
6
|
+
* TUI modal, IPC-backed runner, future web renderer — can render and
|
|
7
|
+
* respond to. The schemas live in core so callers on either side of an
|
|
8
|
+
* adapter (tool author, TUI, IPC protocol) validate against the same
|
|
9
|
+
* definitions rather than each package maintaining a drift-prone copy.
|
|
10
|
+
*
|
|
11
|
+
* Kept separate from a concrete tool factory so the TUI can import the
|
|
12
|
+
* types without pulling in a tool that closes over an `AskUserService`.
|
|
13
|
+
*/
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
//#region Schemas
|
|
16
|
+
export const AskUserOptionSchema = z.object({
|
|
17
|
+
label: z.string().min(1).describe('The display text for this option. Concise (1–5 words).'),
|
|
18
|
+
description: z
|
|
19
|
+
.string()
|
|
20
|
+
.describe('Explanation of what this option means or what will happen if chosen.'),
|
|
21
|
+
preview: z
|
|
22
|
+
.string()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('Optional preview content rendered when this option is focused. Markdown (or HTML fragment) for side-by-side visual comparison.'),
|
|
25
|
+
});
|
|
26
|
+
export const AskUserQuestionSchema = z.object({
|
|
27
|
+
question: z
|
|
28
|
+
.string()
|
|
29
|
+
.min(1)
|
|
30
|
+
.describe('The complete question. Should be clear, specific, and end with a question mark.'),
|
|
31
|
+
header: z
|
|
32
|
+
.string()
|
|
33
|
+
.min(1)
|
|
34
|
+
.max(12)
|
|
35
|
+
.describe('Very short label displayed as a chip/tag (1–12 chars, inclusive).'),
|
|
36
|
+
options: z
|
|
37
|
+
.array(AskUserOptionSchema)
|
|
38
|
+
.min(2)
|
|
39
|
+
.max(4)
|
|
40
|
+
.describe('2–4 distinct choices. An "Other" option is added automatically.'),
|
|
41
|
+
multiSelect: z
|
|
42
|
+
.boolean()
|
|
43
|
+
.default(false)
|
|
44
|
+
.describe('When true, users may select multiple options for this question.'),
|
|
45
|
+
});
|
|
46
|
+
export const AskUserInputSchema = z.object({
|
|
47
|
+
questions: z
|
|
48
|
+
.array(AskUserQuestionSchema)
|
|
49
|
+
.min(1)
|
|
50
|
+
.max(4)
|
|
51
|
+
.describe('1–4 questions to ask the user.')
|
|
52
|
+
// Question text doubles as the answers-map key. Two questions with the
|
|
53
|
+
// same text would silently collapse, so reject duplicates at parse time.
|
|
54
|
+
.refine((qs) => new Set(qs.map((q) => q.question)).size === qs.length, {
|
|
55
|
+
message: 'Question texts must be unique — duplicates would collapse in the answers map.',
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
export const AskUserAnnotationSchema = z.object({
|
|
59
|
+
notes: z.string().optional().describe('Free-text notes the user added to their selection.'),
|
|
60
|
+
preview: z
|
|
61
|
+
.string()
|
|
62
|
+
.optional()
|
|
63
|
+
.describe('The preview content of the selected option, if the question used previews.'),
|
|
64
|
+
});
|
|
65
|
+
export const AskUserOutputSchema = z.object({
|
|
66
|
+
answers: z
|
|
67
|
+
.record(z.string(), z.string())
|
|
68
|
+
.describe('Map from question text to the user\'s answer (label or custom "Other" text).'),
|
|
69
|
+
annotations: z
|
|
70
|
+
.record(z.string(), AskUserAnnotationSchema)
|
|
71
|
+
.optional()
|
|
72
|
+
.describe('Optional per-question annotations (preview content of selected option, notes).'),
|
|
73
|
+
});
|
|
74
|
+
//#endregion
|