Skip to content

Commit 638508d

Browse files
committed
Harden runtime lifecycle and Effect boundaries
1 parent 521149a commit 638508d

48 files changed

Lines changed: 1405 additions & 550 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bun.lock

Lines changed: 22 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,19 @@
77
"url": "https://github.com/theseus-run/theseus"
88
},
99
"homepage": "https://theseus.run",
10-
"workspaces": [
11-
"packages/*"
12-
],
10+
"workspaces": {
11+
"packages": [
12+
"packages/*"
13+
],
14+
"catalogs": {
15+
"effect": {
16+
"effect": "4.0.0-beta.59",
17+
"@effect/platform-bun": "4.0.0-beta.59",
18+
"@effect/sql-sqlite-bun": "4.0.0-beta.59",
19+
"@effect/language-service": "0.80.0"
20+
}
21+
}
22+
},
1323
"scripts": {
1424
"dev": "bun run --parallel dev:server dev:web",
1525
"dev:server": "THESEUS_PORT=4800 bun --watch packages/theseus-server/src/index.ts .",
@@ -24,7 +34,7 @@
2434
},
2535
"devDependencies": {
2636
"@biomejs/biome": "2.4.8",
27-
"@effect/language-service": "0.80.0",
37+
"@effect/language-service": "catalog:effect",
2838
"typescript": "6.0.3"
2939
}
3040
}

packages/icarus-web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"@theseus.run/tools": "workspace:*",
1919
"class-variance-authority": "^0.7.1",
2020
"clsx": "^2.1.1",
21-
"effect": "4.0.0-beta.50",
21+
"effect": "catalog:effect",
2222
"lucide-react": "^0.513.0",
2323
"react": "^19.1.0",
2424
"react-dom": "^19.1.0",

packages/icarus-web/src/lib/rpc-client.ts

Lines changed: 23 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -5,177 +5,36 @@
55
* schema codecs, and stream lifecycle are delegated to Effect RPC.
66
*/
77

8-
import { TheseusRpc } from "@theseus.run/core/Rpc";
9-
import { Effect, Exit, Layer, Scope, Stream } from "effect";
8+
import {
9+
type DispatchEventEntrySchema,
10+
type DispatchEventSchema,
11+
type DispatchSessionSchema,
12+
type MissionSessionSchema,
13+
type ResearchPocEventSchema,
14+
type RuntimeDispatchEventSchema,
15+
TheseusRpc,
16+
type WorkTreeNodeSessionSchema,
17+
} from "@theseus.run/core/Rpc";
18+
import { Effect, Exit, Layer, type Schema, Scope, Stream } from "effect";
1019
import { RpcClient, RpcSerialization } from "effect/unstable/rpc";
1120
import * as Socket from "effect/unstable/socket/Socket";
1221

1322
// ---------------------------------------------------------------------------
1423
// Types
1524
// ---------------------------------------------------------------------------
1625

17-
/** Serialized dispatch event matching DispatchEventSchema */
18-
export interface CortexSignal {
19-
readonly id: string;
20-
readonly nodeId: string;
21-
readonly slot:
22-
| "harness"
23-
| "workspace"
24-
| "mission"
25-
| "work-node"
26-
| "observations"
27-
| "history"
28-
| "recall";
29-
readonly authority: "system" | "developer" | "user" | "assistant" | "tool";
30-
readonly priority: number;
31-
readonly text: string;
32-
}
33-
34-
export interface DispatchEvent {
35-
readonly _tag: string;
36-
readonly name?: string;
37-
readonly iteration?: number;
38-
readonly signals?: ReadonlyArray<CortexSignal>;
39-
readonly historyMessageCount?: number;
40-
readonly cortexMessageCount?: number;
41-
readonly promptMessageCount?: number;
42-
readonly tool?: string;
43-
readonly content?: string;
44-
readonly structured?: unknown;
45-
readonly args?: unknown;
46-
readonly error?: unknown;
47-
readonly isError?: boolean;
48-
readonly satellite?: string;
49-
readonly phase?: string;
50-
readonly action?: string;
51-
readonly injection?: string;
52-
readonly detail?: string | null;
53-
readonly reason?: string;
54-
readonly result?: {
55-
readonly dispatchId: string;
56-
readonly name: string;
57-
readonly content: string;
58-
readonly usage: { readonly inputTokens: number; readonly outputTokens: number };
59-
};
60-
}
61-
62-
export interface DispatchEventEntry {
63-
readonly dispatchId: string;
64-
readonly timestamp: number;
65-
readonly event: DispatchEvent;
66-
}
67-
68-
export interface MissionSession {
69-
readonly missionId: string;
70-
readonly capsuleId: string;
71-
readonly goal: string;
72-
readonly criteria: ReadonlyArray<string>;
73-
readonly state: "pending" | "running" | "done" | "failed";
74-
}
75-
76-
export interface DispatchSession {
77-
readonly workNodeId: string;
78-
readonly parentWorkNodeId?: string | null;
79-
readonly kind: "dispatch";
80-
readonly relation: WorkNodeRelation;
81-
readonly label: string;
82-
readonly control: WorkNodeControlDescriptor;
83-
readonly dispatchId: string;
84-
readonly missionId: string;
85-
readonly capsuleId: string;
86-
readonly name: string;
87-
readonly modelRequest?: ModelRequest | null;
88-
readonly iteration: number;
89-
readonly state: WorkNodeState;
90-
readonly usage: { readonly inputTokens: number; readonly outputTokens: number };
91-
}
92-
93-
export interface WorkNodeSession {
94-
readonly workNodeId: string;
95-
readonly missionId: string;
96-
readonly capsuleId: string;
97-
readonly parentWorkNodeId?: string | null;
98-
readonly kind: "dispatch" | "task" | "external";
99-
readonly relation: WorkNodeRelation;
100-
readonly label: string;
101-
readonly state: WorkNodeState;
102-
readonly control: WorkNodeControlDescriptor;
103-
readonly startedAt?: number | null;
104-
readonly completedAt?: number | null;
105-
}
106-
107-
export type WorkNodeRelation = "root" | "delegated" | "continued" | "branched";
108-
export type WorkNodeState =
109-
| "pending"
110-
| "running"
111-
| "paused"
112-
| "blocked"
113-
| "done"
114-
| "failed"
115-
| "aborted";
116-
export type WorkControlCapability =
117-
| { readonly _tag: "Supported" }
118-
| { readonly _tag: "Unsupported"; readonly reason: string };
119-
export interface WorkNodeControlDescriptor {
120-
readonly interrupt: WorkControlCapability;
121-
readonly injectGuidance: WorkControlCapability;
122-
readonly pause: WorkControlCapability;
123-
readonly resume: WorkControlCapability;
124-
readonly stop: WorkControlCapability;
125-
readonly requestStatus: WorkControlCapability;
126-
}
127-
export type ModelRequest =
128-
| {
129-
readonly provider: "openai";
130-
readonly model: string;
131-
readonly maxOutputTokens?: number | null;
132-
readonly reasoningEffort?: "low" | "medium" | "high" | "xhigh" | null;
133-
readonly textVerbosity?: "low" | "medium" | "high" | null;
134-
}
135-
| {
136-
readonly provider: "copilot";
137-
readonly model: string;
138-
readonly maxTokens?: number | null;
139-
};
140-
141-
export type RuntimeDispatchEvent =
142-
| {
143-
readonly _tag: "WorkNodeStarted";
144-
readonly node: WorkNodeSession;
145-
}
146-
| {
147-
readonly _tag: "DispatchSessionStarted";
148-
readonly session: DispatchSession;
149-
}
150-
| {
151-
readonly _tag: "DispatchEvent";
152-
readonly workNodeId: string;
153-
readonly dispatchId: string;
154-
readonly missionId: string;
155-
readonly capsuleId: string;
156-
readonly event: DispatchEvent;
157-
}
158-
| {
159-
readonly _tag: "WorkNodeStateChanged";
160-
readonly workNodeId: string;
161-
readonly missionId: string;
162-
readonly state: WorkNodeState;
163-
readonly reason?: string | null;
164-
}
165-
| {
166-
readonly _tag: "RuntimeProcessFailed";
167-
readonly workNodeId: string;
168-
readonly missionId: string;
169-
readonly process: string;
170-
readonly reason: string;
171-
};
172-
173-
export type ResearchPocEvent =
174-
| {
175-
readonly _tag: "MissionCreated";
176-
readonly mission: MissionSession;
177-
}
178-
| RuntimeDispatchEvent;
26+
export type DispatchEvent = Schema.Schema.Type<typeof DispatchEventSchema>;
27+
export type DispatchEventEntry = Schema.Schema.Type<typeof DispatchEventEntrySchema>;
28+
export type MissionSession = Schema.Schema.Type<typeof MissionSessionSchema>;
29+
export type DispatchSession = Schema.Schema.Type<typeof DispatchSessionSchema>;
30+
export type WorkNodeSession = Schema.Schema.Type<typeof WorkTreeNodeSessionSchema>;
31+
export type WorkNodeRelation = WorkNodeSession["relation"];
32+
export type WorkNodeState = WorkNodeSession["state"];
33+
export type WorkControlCapability = WorkNodeSession["control"]["pause"];
34+
export type WorkNodeControlDescriptor = WorkNodeSession["control"];
35+
export type ModelRequest = NonNullable<DispatchSession["modelRequest"]>;
36+
export type RuntimeDispatchEvent = Schema.Schema.Type<typeof RuntimeDispatchEventSchema>;
37+
export type ResearchPocEvent = Schema.Schema.Type<typeof ResearchPocEventSchema>;
17938

18039
export type ConnectionState = "connecting" | "connected" | "disconnected";
18140
export type ConnectionListener = (state: ConnectionState) => void;

packages/icarus-web/src/routes/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,14 @@ const applyResearchPocEvent = (
211211
}));
212212
}),
213213
Match.tag("DispatchEvent", ({ dispatchId, event }) => {
214+
const name = "name" in event ? event.name : dispatchId;
214215
setState((current) => ({
215216
...current,
216217
transcripts: mergeBy(
217218
current.transcripts,
218219
{
219220
dispatchId,
220-
name: event.name ?? dispatchId,
221+
name,
221222
events: [
222223
...(current.transcripts.find((transcript) => transcript.dispatchId === dispatchId)
223224
?.events ?? []),
@@ -228,5 +229,7 @@ const applyResearchPocEvent = (
228229
),
229230
}));
230231
}),
232+
Match.tag("WorkNodeStateChanged", () => undefined),
233+
Match.tag("RuntimeProcessFailed", () => undefined),
231234
Match.exhaustive,
232235
);

0 commit comments

Comments
 (0)