@zachwill/pi-orchestrate 0.8.0 → 0.9.2

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.
@@ -1,41 +1,18 @@
1
1
  import { Schema } from "effect";
2
- import type { RunId, WorkerId } from "./domain.js";
2
+ import {
3
+ RunId,
4
+ WorkerAbortedOutcome,
5
+ WorkerCompletedOutcome,
6
+ WorkerFailedOutcome,
7
+ WorkerId,
8
+ WorkerReadyOutcome,
9
+ WorkerResponseOutcome,
10
+ WorkerUsage,
11
+ } from "./domain.js";
3
12
 
4
- const NonnegativeFinite = Schema.Finite.check(Schema.isGreaterThanOrEqualTo(0));
5
13
  const NonnegativeInteger = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
6
14
  const PositiveInteger = Schema.Int.check(Schema.isGreaterThan(0));
7
15
 
8
- const WorkerUsage = Schema.Struct({
9
- input: NonnegativeFinite,
10
- output: NonnegativeFinite,
11
- cacheRead: NonnegativeFinite,
12
- cacheWrite: NonnegativeFinite,
13
- cost: NonnegativeFinite,
14
- contextTokens: NonnegativeFinite,
15
- turns: NonnegativeInteger,
16
- });
17
-
18
- const WorkerOutcome = Schema.Union([
19
- Schema.Struct({
20
- status: Schema.Literal("completed"),
21
- assistantText: Schema.String,
22
- }),
23
- Schema.Struct({
24
- status: Schema.Literal("ready"),
25
- assistantText: Schema.String,
26
- }),
27
- Schema.Struct({
28
- status: Schema.Literal("failed"),
29
- message: Schema.String,
30
- assistantText: Schema.optionalKey(Schema.String),
31
- }),
32
- Schema.Struct({
33
- status: Schema.Literal("aborted"),
34
- message: Schema.optionalKey(Schema.String),
35
- assistantText: Schema.optionalKey(Schema.String),
36
- }),
37
- ]);
38
-
39
16
  const FailureStage = Schema.Literals([
40
17
  "startup",
41
18
  "prompt",
@@ -48,15 +25,15 @@ export const WorkerSettlementDetails = Schema.Struct({
48
25
  eventId: Schema.String,
49
26
  sequence: PositiveInteger,
50
27
  ownerSessionId: Schema.String,
51
- runId: Schema.String,
52
- workerId: Schema.String,
28
+ runId: RunId,
29
+ workerId: WorkerId,
53
30
  generation: PositiveInteger,
54
31
  mode: Schema.Literals(["async", "inline"]),
55
32
  worker: Schema.String,
56
33
  title: Schema.String,
57
34
  lifecycle: Schema.Literals(["one-shot", "interactive"]),
58
35
  status: Schema.Literals(["completed", "ready", "failed", "aborted"]),
59
- outcome: WorkerOutcome,
36
+ outcome: WorkerResponseOutcome,
60
37
  usage: WorkerUsage,
61
38
  startedAt: NonnegativeInteger,
62
39
  settledAt: NonnegativeInteger,
@@ -107,14 +84,9 @@ export type SettlementFailureStage = NonNullable<
107
84
  WorkerSettlementDetails["failureStage"]
108
85
  >;
109
86
 
110
- /** Runtime refinement preserves the nominal IDs already allocated by the domain. */
111
- export type WorkerSettlement = Omit<
112
- WorkerSettlementDetails,
113
- "runId" | "workerId"
114
- > & {
115
- readonly runId: RunId;
116
- readonly workerId: WorkerId;
117
- };
87
+ export type WorkerSettlement = Schema.Schema.Type<
88
+ typeof WorkerSettlementDetails
89
+ >;
118
90
 
119
91
  const decodeCurrentWorkerSettlement = Schema.decodeUnknownResult(
120
92
  WorkerSettlementDetails,
@@ -123,3 +95,92 @@ const decodeCurrentWorkerSettlement = Schema.decodeUnknownResult(
123
95
  export function decodePersistedWorkerSettlementDetails(value: unknown) {
124
96
  return decodeCurrentWorkerSettlement(value);
125
97
  }
98
+
99
+ const InlineWorkerOutcome = Schema.Union([
100
+ WorkerCompletedOutcome.pipe(
101
+ Schema.encodeKeys({ assistantText: "assistant_text" }),
102
+ ),
103
+ WorkerReadyOutcome.pipe(
104
+ Schema.encodeKeys({ assistantText: "assistant_text" }),
105
+ ),
106
+ WorkerFailedOutcome.pipe(
107
+ Schema.encodeKeys({ assistantText: "assistant_text" }),
108
+ ),
109
+ WorkerAbortedOutcome.pipe(
110
+ Schema.encodeKeys({ assistantText: "assistant_text" }),
111
+ ),
112
+ ]);
113
+
114
+ const InlineWorkerUsage = WorkerUsage.pipe(
115
+ Schema.encodeKeys({
116
+ cacheRead: "cache_read",
117
+ cacheWrite: "cache_write",
118
+ contextTokens: "context_tokens",
119
+ }),
120
+ );
121
+
122
+ /** Tool transport projection derived from the canonical settlement field schemas. */
123
+ export const InlineWorkerSettlementDetails = Schema.Struct({
124
+ workerId: WorkerSettlementDetails.fields.workerId,
125
+ worker: WorkerSettlementDetails.fields.worker,
126
+ title: WorkerSettlementDetails.fields.title,
127
+ status: WorkerSettlementDetails.fields.status,
128
+ outcome: InlineWorkerOutcome,
129
+ usage: InlineWorkerUsage,
130
+ startedAt: WorkerSettlementDetails.fields.startedAt,
131
+ settledAt: WorkerSettlementDetails.fields.settledAt,
132
+ sessionFile: WorkerSettlementDetails.fields.sessionFile,
133
+ }).pipe(
134
+ Schema.encodeKeys({
135
+ workerId: "worker_id",
136
+ startedAt: "started_at",
137
+ settledAt: "settled_at",
138
+ sessionFile: "session_file",
139
+ }),
140
+ ).check(
141
+ Schema.makeFilter((settlement) => {
142
+ if (settlement.outcome.status !== settlement.status) {
143
+ return "outcome status must match settlement status";
144
+ }
145
+ if (settlement.settledAt < settlement.startedAt) {
146
+ return "settlement timestamp must not precede start timestamp";
147
+ }
148
+ }),
149
+ );
150
+
151
+ export interface InlineWorkerSettlementDetails
152
+ extends Schema.Schema.Type<typeof InlineWorkerSettlementDetails> {}
153
+
154
+ export const InlineWorkerToolDetails = Schema.Struct({
155
+ mode: Schema.Literal("inline"),
156
+ runId: Schema.optionalKey(WorkerSettlementDetails.fields.runId),
157
+ ownerSessionId: Schema.optionalKey(
158
+ WorkerSettlementDetails.fields.ownerSessionId,
159
+ ),
160
+ result: InlineWorkerSettlementDetails,
161
+ }).pipe(
162
+ Schema.encodeKeys({
163
+ runId: "run_id",
164
+ ownerSessionId: "owner_session_id",
165
+ }),
166
+ );
167
+
168
+ export interface InlineWorkerToolDetails
169
+ extends Schema.Schema.Type<typeof InlineWorkerToolDetails> {}
170
+
171
+ const decodeInlineWorkerToolDetailsResult = Schema.decodeUnknownResult(
172
+ InlineWorkerToolDetails,
173
+ );
174
+ const encodeInlineWorkerToolDetailsSync = Schema.encodeSync(
175
+ InlineWorkerToolDetails,
176
+ );
177
+
178
+ export function decodeInlineWorkerToolDetails(value: unknown) {
179
+ return decodeInlineWorkerToolDetailsResult(value);
180
+ }
181
+
182
+ export function encodeInlineWorkerToolDetails(
183
+ value: InlineWorkerToolDetails,
184
+ ) {
185
+ return encodeInlineWorkerToolDetailsSync(value);
186
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zachwill/pi-orchestrate",
3
- "version": "0.8.0",
3
+ "version": "0.9.2",
4
4
  "type": "module",
5
5
  "description": "Concurrent worker orchestration for Pi",
6
6
  "files": ["extension/", "examples/", "README.md", "LICENSE"],
@@ -1,85 +0,0 @@
1
- import { Cause, Context, Effect, FiberMap, Layer, ManagedRuntime } from "effect";
2
-
3
- export type WorkflowDefectHandler = (error: unknown) => void;
4
-
5
- export interface WorkflowScheduler<Key> {
6
- /** Starts a workflow immediately, interrupting and replacing the previous workflow at the key. */
7
- start(
8
- key: Key,
9
- workflow: Effect.Effect<void, never>,
10
- onDefect: WorkflowDefectHandler,
11
- ): void;
12
- /** Interrupts the current workflow at the key and waits for its fiber to settle. */
13
- remove(key: Key): Promise<void>;
14
- /** Interrupts every retained workflow and closes the scheduler scope. */
15
- close(): Promise<void>;
16
- }
17
-
18
- interface WorkflowSupervisorService {
19
- readonly start: (
20
- key: unknown,
21
- workflow: Effect.Effect<void, never>,
22
- ) => void;
23
- readonly remove: (key: unknown) => Effect.Effect<void>;
24
- }
25
-
26
- class WorkflowSupervisor extends Context.Service<
27
- WorkflowSupervisor,
28
- WorkflowSupervisorService
29
- >()("@zachwill/pi-orchestrate/WorkflowSupervisor") {}
30
-
31
- const workflowSupervisorLayer = Layer.effect(
32
- WorkflowSupervisor,
33
- Effect.gen(function* () {
34
- const fibers = yield* FiberMap.make<unknown, void, never>();
35
- const run = yield* FiberMap.runtime(fibers)<never>();
36
- return WorkflowSupervisor.of({
37
- start(key, workflow) {
38
- run(key, workflow);
39
- },
40
- remove: (key) => FiberMap.remove(fibers, key),
41
- });
42
- }),
43
- );
44
-
45
- class EffectWorkflowScheduler<Key> implements WorkflowScheduler<Key> {
46
- private readonly managedRuntime = ManagedRuntime.make(workflowSupervisorLayer);
47
- private readonly supervisor = this.managedRuntime.runSync(WorkflowSupervisor);
48
- private closePromise: Promise<void> | undefined;
49
-
50
- start(
51
- key: Key,
52
- workflow: Effect.Effect<void, never>,
53
- onDefect: WorkflowDefectHandler,
54
- ): void {
55
- const supervised = workflow.pipe(
56
- Effect.catchCause((cause) => {
57
- if (!Cause.hasInterruptsOnly(cause)) {
58
- return Effect.sync(() => {
59
- try {
60
- onDefect(Cause.squash(cause));
61
- } catch {
62
- // Defect reporting must not become another unsupervised defect.
63
- }
64
- });
65
- }
66
- return Effect.void;
67
- }),
68
- );
69
-
70
- this.supervisor.start(key, supervised);
71
- }
72
-
73
- remove(key: Key): Promise<void> {
74
- return this.managedRuntime.runPromise(this.supervisor.remove(key));
75
- }
76
-
77
- close(): Promise<void> {
78
- this.closePromise ??= this.managedRuntime.dispose();
79
- return this.closePromise;
80
- }
81
- }
82
-
83
- export function createWorkflowScheduler<Key>(): WorkflowScheduler<Key> {
84
- return new EffectWorkflowScheduler<Key>();
85
- }