@openshain/core 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/load.d.ts +10 -0
- package/dist/config/load.js +66 -0
- package/dist/config/schema.d.ts +84 -0
- package/dist/config/schema.js +96 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.js +30 -0
- package/dist/ids.d.ts +11 -0
- package/dist/ids.js +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +20 -0
- package/dist/model/types.d.ts +57 -0
- package/dist/model/types.js +0 -0
- package/dist/runtime.d.ts +46 -0
- package/dist/runtime.js +144 -0
- package/dist/schemas.d.ts +9 -0
- package/dist/schemas.js +44 -0
- package/dist/tool/load-module.d.ts +6 -0
- package/dist/tool/load-module.js +42 -0
- package/dist/tool/paths.d.ts +17 -0
- package/dist/tool/paths.js +82 -0
- package/dist/tool/registry.d.ts +30 -0
- package/dist/tool/registry.js +68 -0
- package/dist/tool/types.d.ts +44 -0
- package/dist/tool/types.js +15 -0
- package/dist/tool/validate.d.ts +14 -0
- package/dist/tool/validate.js +68 -0
- package/dist/uuid.d.ts +1 -0
- package/dist/uuid.js +33 -0
- package/dist/work/artifacts.d.ts +7 -0
- package/dist/work/artifacts.js +20 -0
- package/dist/work/event-log.d.ts +28 -0
- package/dist/work/event-log.js +140 -0
- package/dist/work/events.d.ts +311 -0
- package/dist/work/events.js +344 -0
- package/dist/work/lock.d.ts +13 -0
- package/dist/work/lock.js +80 -0
- package/dist/work/projection.d.ts +31 -0
- package/dist/work/projection.js +130 -0
- package/dist/work/store.d.ts +58 -0
- package/dist/work/store.js +174 -0
- package/dist/work/work.d.ts +86 -0
- package/dist/work/work.js +149 -0
- package/package.json +16 -5
- package/src/ids.ts +3 -2
- package/src/index.ts +1 -0
- package/src/uuid.ts +33 -0
- package/src/work/projection.ts +1 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { appendFile, mkdir, readFile, stat } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { OpenshainError } from "../errors.js";
|
|
4
|
+
import { newEventId } from "../ids.js";
|
|
5
|
+
import { eventFromFile, eventToFile, } from "./events.js";
|
|
6
|
+
export const EVENTS_FILE_NAME = "events.jsonl";
|
|
7
|
+
/** Appends to one file are serialized within the process, so two instances cannot interleave the size check and the write. */
|
|
8
|
+
const appendQueues = new Map();
|
|
9
|
+
function serialized(path, task) {
|
|
10
|
+
const previous = appendQueues.get(path) ?? Promise.resolve();
|
|
11
|
+
const run = previous.then(task, task);
|
|
12
|
+
const settled = run
|
|
13
|
+
.catch(() => undefined)
|
|
14
|
+
.then(() => {
|
|
15
|
+
if (appendQueues.get(path) === settled)
|
|
16
|
+
appendQueues.delete(path);
|
|
17
|
+
});
|
|
18
|
+
appendQueues.set(path, settled);
|
|
19
|
+
return run;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Append-only log of one work's events. The file is the source of truth.
|
|
23
|
+
*
|
|
24
|
+
* Every line is checked on open and on read; a line that cannot be read stops
|
|
25
|
+
* the reader. Every event is checked on append by reading its own line back
|
|
26
|
+
* before it is written, so what is written can always be read. A change to the
|
|
27
|
+
* file by someone else between two operations of this instance is refused.
|
|
28
|
+
*/
|
|
29
|
+
export class EventLog {
|
|
30
|
+
path;
|
|
31
|
+
workId;
|
|
32
|
+
nextSeq;
|
|
33
|
+
size;
|
|
34
|
+
constructor(path, workId, nextSeq, size) {
|
|
35
|
+
this.path = path;
|
|
36
|
+
this.workId = workId;
|
|
37
|
+
this.nextSeq = nextSeq;
|
|
38
|
+
this.size = size;
|
|
39
|
+
}
|
|
40
|
+
/** Opens (creating the directory if needed) and checks the existing log end to end. */
|
|
41
|
+
static async open(dir, workId) {
|
|
42
|
+
await mkdir(dir, { recursive: true });
|
|
43
|
+
const path = join(dir, EVENTS_FILE_NAME);
|
|
44
|
+
const { events, size } = await readAll(path, workId);
|
|
45
|
+
const last = events.at(-1);
|
|
46
|
+
return new EventLog(path, workId, (last?.seq ?? 0) + 1, size);
|
|
47
|
+
}
|
|
48
|
+
async append(input) {
|
|
49
|
+
const now = new Date().toISOString();
|
|
50
|
+
const event = {
|
|
51
|
+
v: 1,
|
|
52
|
+
id: newEventId(),
|
|
53
|
+
workId: this.workId,
|
|
54
|
+
seq: this.nextSeq,
|
|
55
|
+
type: input.type,
|
|
56
|
+
occurredAt: input.occurredAt ?? now,
|
|
57
|
+
recordedAt: now,
|
|
58
|
+
payload: input.payload,
|
|
59
|
+
};
|
|
60
|
+
let line;
|
|
61
|
+
try {
|
|
62
|
+
line = `${JSON.stringify(eventToFile(event))}\n`;
|
|
63
|
+
eventFromFile(JSON.parse(line));
|
|
64
|
+
}
|
|
65
|
+
catch (cause) {
|
|
66
|
+
throw new OpenshainError("invalid_event", `${input.type} event cannot be read back once written: ${cause.message}`, { cause });
|
|
67
|
+
}
|
|
68
|
+
await serialized(this.path, async () => {
|
|
69
|
+
const current = await fileSize(this.path);
|
|
70
|
+
if (current !== this.size) {
|
|
71
|
+
throw new OpenshainError("concurrent_write", `${this.path} changed since it was opened (expected ${this.size} bytes, found ${current}); another writer is active`);
|
|
72
|
+
}
|
|
73
|
+
await appendFile(this.path, line, "utf8");
|
|
74
|
+
this.size += Buffer.byteLength(line, "utf8");
|
|
75
|
+
this.nextSeq += 1;
|
|
76
|
+
});
|
|
77
|
+
return event;
|
|
78
|
+
}
|
|
79
|
+
async read() {
|
|
80
|
+
return (await readAll(this.path, this.workId)).events;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function fileSize(path) {
|
|
84
|
+
try {
|
|
85
|
+
return (await stat(path)).size;
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
if (err.code === "ENOENT")
|
|
89
|
+
return 0;
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function readAll(path, workId) {
|
|
94
|
+
let text;
|
|
95
|
+
try {
|
|
96
|
+
text = await readFile(path, "utf8");
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
if (err.code === "ENOENT")
|
|
100
|
+
return { events: [], size: 0 };
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
103
|
+
const corrupt = (detail, cause) => new OpenshainError("corrupt_log", `${path}: ${detail}`, { cause });
|
|
104
|
+
if (text.length > 0 && !text.endsWith("\n")) {
|
|
105
|
+
throw corrupt("does not end with a newline; the last write did not complete");
|
|
106
|
+
}
|
|
107
|
+
const events = [];
|
|
108
|
+
const lines = text.split("\n");
|
|
109
|
+
lines.forEach((line, index) => {
|
|
110
|
+
const lineNo = index + 1;
|
|
111
|
+
if (line === "") {
|
|
112
|
+
if (index === lines.length - 1)
|
|
113
|
+
return; // trailing newline
|
|
114
|
+
throw corrupt(`line ${lineNo} is empty`);
|
|
115
|
+
}
|
|
116
|
+
let parsed;
|
|
117
|
+
try {
|
|
118
|
+
parsed = JSON.parse(line);
|
|
119
|
+
}
|
|
120
|
+
catch (cause) {
|
|
121
|
+
throw corrupt(`line ${lineNo} is not valid JSON`, cause);
|
|
122
|
+
}
|
|
123
|
+
let event;
|
|
124
|
+
try {
|
|
125
|
+
event = eventFromFile(parsed);
|
|
126
|
+
}
|
|
127
|
+
catch (cause) {
|
|
128
|
+
throw corrupt(`line ${lineNo} is not a valid event: ${cause.message}`, cause);
|
|
129
|
+
}
|
|
130
|
+
if (event.workId !== workId) {
|
|
131
|
+
throw corrupt(`line ${lineNo} belongs to ${event.workId}, expected ${workId}`);
|
|
132
|
+
}
|
|
133
|
+
const expectedSeq = events.length + 1;
|
|
134
|
+
if (event.seq !== expectedSeq) {
|
|
135
|
+
throw corrupt(`line ${lineNo} has seq ${event.seq}, expected ${expectedSeq}`);
|
|
136
|
+
}
|
|
137
|
+
events.push(event);
|
|
138
|
+
});
|
|
139
|
+
return { events, size: Buffer.byteLength(text, "utf8") };
|
|
140
|
+
}
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { EventId, WorkId } from "../ids.ts";
|
|
3
|
+
export type StopReason = "end_turn" | "tool_call" | "max_tokens" | "refusal" | "other";
|
|
4
|
+
export type AssistantPart = {
|
|
5
|
+
type: "text";
|
|
6
|
+
text: string;
|
|
7
|
+
} | {
|
|
8
|
+
type: "tool_call";
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
input: unknown;
|
|
12
|
+
} | {
|
|
13
|
+
type: "opaque";
|
|
14
|
+
provider: string;
|
|
15
|
+
data: unknown;
|
|
16
|
+
};
|
|
17
|
+
export type ToolContent = {
|
|
18
|
+
type: "text";
|
|
19
|
+
text: string;
|
|
20
|
+
} | {
|
|
21
|
+
type: "json";
|
|
22
|
+
value: unknown;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* A file a work produced. `missing` means the runtime could not read it when the work ended; the
|
|
26
|
+
* hash is then the tool's report. `claimed` means an agent named it but no tool of this work wrote
|
|
27
|
+
* it; the hash is the runtime's, but nothing in the record ties the file to this work's calls.
|
|
28
|
+
*/
|
|
29
|
+
export type Artifact = {
|
|
30
|
+
path: string;
|
|
31
|
+
sha256: string;
|
|
32
|
+
missing?: true;
|
|
33
|
+
claimed?: true;
|
|
34
|
+
};
|
|
35
|
+
export interface ModelUsage {
|
|
36
|
+
/** Every input token, including the ones read from or written to a prompt cache. */
|
|
37
|
+
inputTokens: number;
|
|
38
|
+
outputTokens: number;
|
|
39
|
+
/** The part of inputTokens served from a prompt cache. */
|
|
40
|
+
cachedInputTokens?: number;
|
|
41
|
+
/** The part of inputTokens written to a prompt cache. */
|
|
42
|
+
cacheWriteTokens?: number;
|
|
43
|
+
/** The part of outputTokens spent on reasoning. */
|
|
44
|
+
reasoningTokens?: number;
|
|
45
|
+
}
|
|
46
|
+
export declare const TOOL_REJECTION_CODES: readonly ["schema_mismatch", "unknown_tool", "not_allowed", "reserved_path", "outside_workspace", "invalid_path"];
|
|
47
|
+
export type ToolRejectionCode = (typeof TOOL_REJECTION_CODES)[number];
|
|
48
|
+
export interface EventPayloads {
|
|
49
|
+
"work.created": {
|
|
50
|
+
objective: string;
|
|
51
|
+
principal: string;
|
|
52
|
+
profession: string;
|
|
53
|
+
type: string;
|
|
54
|
+
/** The work this one was started from, such as the session that asked for it. */
|
|
55
|
+
parent?: string;
|
|
56
|
+
/** The name the model goes by in this work. A session picks it; the works it starts carry the same one. */
|
|
57
|
+
agentName?: string;
|
|
58
|
+
};
|
|
59
|
+
"work.status_changed": {
|
|
60
|
+
from: string;
|
|
61
|
+
to: string;
|
|
62
|
+
reason: string;
|
|
63
|
+
};
|
|
64
|
+
"model.requested": {
|
|
65
|
+
provider: string;
|
|
66
|
+
model: string;
|
|
67
|
+
messageCount: number;
|
|
68
|
+
toolNames: string[];
|
|
69
|
+
};
|
|
70
|
+
"model.completed": {
|
|
71
|
+
stopReason: StopReason;
|
|
72
|
+
content: AssistantPart[];
|
|
73
|
+
raw?: unknown;
|
|
74
|
+
};
|
|
75
|
+
"model.failed": {
|
|
76
|
+
code: string;
|
|
77
|
+
message: string;
|
|
78
|
+
};
|
|
79
|
+
"tool.called": {
|
|
80
|
+
callId: string;
|
|
81
|
+
provider: string;
|
|
82
|
+
name: string;
|
|
83
|
+
input: unknown;
|
|
84
|
+
};
|
|
85
|
+
"tool.completed": {
|
|
86
|
+
callId: string;
|
|
87
|
+
content: ToolContent[];
|
|
88
|
+
isError: boolean;
|
|
89
|
+
observation?: {
|
|
90
|
+
source: string;
|
|
91
|
+
retrievedAt: string;
|
|
92
|
+
};
|
|
93
|
+
after?: Artifact[];
|
|
94
|
+
};
|
|
95
|
+
"tool.rejected": {
|
|
96
|
+
callId: string;
|
|
97
|
+
name: string;
|
|
98
|
+
code: ToolRejectionCode;
|
|
99
|
+
reason: string;
|
|
100
|
+
};
|
|
101
|
+
"human.input_requested": {
|
|
102
|
+
callId: string;
|
|
103
|
+
question: string;
|
|
104
|
+
};
|
|
105
|
+
"human.input_provided": {
|
|
106
|
+
callId: string;
|
|
107
|
+
answer: string;
|
|
108
|
+
};
|
|
109
|
+
/** What the person said in a session. Becomes a user message in the projection. */
|
|
110
|
+
"human.message": {
|
|
111
|
+
text: string;
|
|
112
|
+
};
|
|
113
|
+
"usage.recorded": {
|
|
114
|
+
kind: "model_inference";
|
|
115
|
+
provider: string;
|
|
116
|
+
model: string;
|
|
117
|
+
usage: ModelUsage;
|
|
118
|
+
} | {
|
|
119
|
+
kind: "tool_execution";
|
|
120
|
+
provider: string;
|
|
121
|
+
usage: {
|
|
122
|
+
durationMs: number;
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
"evidence.recorded": {
|
|
126
|
+
claim: string;
|
|
127
|
+
refs: string[];
|
|
128
|
+
artifacts: Artifact[];
|
|
129
|
+
};
|
|
130
|
+
"work.completed": {
|
|
131
|
+
summary: string;
|
|
132
|
+
};
|
|
133
|
+
"work.failed": {
|
|
134
|
+
reason: string;
|
|
135
|
+
detail: string;
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
export type EventType = keyof EventPayloads;
|
|
139
|
+
interface Envelope {
|
|
140
|
+
v: 1;
|
|
141
|
+
id: EventId;
|
|
142
|
+
workId: WorkId;
|
|
143
|
+
seq: number;
|
|
144
|
+
occurredAt: string;
|
|
145
|
+
recordedAt: string;
|
|
146
|
+
}
|
|
147
|
+
export type Event<T extends EventType = EventType> = T extends EventType ? Envelope & {
|
|
148
|
+
type: T;
|
|
149
|
+
payload: EventPayloads[T];
|
|
150
|
+
} : never;
|
|
151
|
+
/** An event whose type this version of the runtime does not know. Kept, not validated. */
|
|
152
|
+
export type UnknownEvent = Envelope & {
|
|
153
|
+
type: string;
|
|
154
|
+
payload: unknown;
|
|
155
|
+
};
|
|
156
|
+
export type AnyEvent = Event | UnknownEvent;
|
|
157
|
+
export declare const payloadFileSchemas: {
|
|
158
|
+
"work.created": z.ZodObject<{
|
|
159
|
+
objective: z.ZodString;
|
|
160
|
+
principal: z.ZodString;
|
|
161
|
+
profession: z.ZodString;
|
|
162
|
+
type: z.ZodString;
|
|
163
|
+
parent: z.ZodOptional<z.ZodString>;
|
|
164
|
+
agent_name: z.ZodOptional<z.ZodString>;
|
|
165
|
+
}, z.core.$loose>;
|
|
166
|
+
"work.status_changed": z.ZodObject<{
|
|
167
|
+
from: z.ZodString;
|
|
168
|
+
to: z.ZodString;
|
|
169
|
+
reason: z.ZodString;
|
|
170
|
+
}, z.core.$loose>;
|
|
171
|
+
"model.requested": z.ZodObject<{
|
|
172
|
+
provider: z.ZodString;
|
|
173
|
+
model: z.ZodString;
|
|
174
|
+
message_count: z.ZodInt;
|
|
175
|
+
tool_names: z.ZodArray<z.ZodString>;
|
|
176
|
+
}, z.core.$loose>;
|
|
177
|
+
"model.completed": z.ZodObject<{
|
|
178
|
+
stop_reason: z.ZodEnum<{
|
|
179
|
+
end_turn: "end_turn";
|
|
180
|
+
max_tokens: "max_tokens";
|
|
181
|
+
other: "other";
|
|
182
|
+
refusal: "refusal";
|
|
183
|
+
tool_call: "tool_call";
|
|
184
|
+
}>;
|
|
185
|
+
content: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
186
|
+
type: z.ZodLiteral<"text">;
|
|
187
|
+
text: z.ZodString;
|
|
188
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
189
|
+
type: z.ZodLiteral<"tool_call">;
|
|
190
|
+
id: z.ZodString;
|
|
191
|
+
name: z.ZodString;
|
|
192
|
+
input: z.ZodUnknown;
|
|
193
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
194
|
+
type: z.ZodLiteral<"opaque">;
|
|
195
|
+
provider: z.ZodString;
|
|
196
|
+
data: z.ZodUnknown;
|
|
197
|
+
}, z.core.$loose>], "type">>;
|
|
198
|
+
raw: z.ZodOptional<z.ZodUnknown>;
|
|
199
|
+
}, z.core.$loose>;
|
|
200
|
+
"model.failed": z.ZodObject<{
|
|
201
|
+
code: z.ZodString;
|
|
202
|
+
message: z.ZodString;
|
|
203
|
+
}, z.core.$loose>;
|
|
204
|
+
"tool.called": z.ZodObject<{
|
|
205
|
+
call_id: z.ZodString;
|
|
206
|
+
provider: z.ZodString;
|
|
207
|
+
name: z.ZodString;
|
|
208
|
+
input: z.ZodUnknown;
|
|
209
|
+
}, z.core.$loose>;
|
|
210
|
+
"tool.completed": z.ZodObject<{
|
|
211
|
+
call_id: z.ZodString;
|
|
212
|
+
content: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
213
|
+
type: z.ZodLiteral<"text">;
|
|
214
|
+
text: z.ZodString;
|
|
215
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
216
|
+
type: z.ZodLiteral<"json">;
|
|
217
|
+
value: z.ZodUnknown;
|
|
218
|
+
}, z.core.$loose>], "type">>;
|
|
219
|
+
is_error: z.ZodBoolean;
|
|
220
|
+
observation: z.ZodOptional<z.ZodObject<{
|
|
221
|
+
source: z.ZodString;
|
|
222
|
+
retrieved_at: z.ZodISODateTime;
|
|
223
|
+
}, z.core.$loose>>;
|
|
224
|
+
after: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
225
|
+
path: z.ZodString;
|
|
226
|
+
sha256: z.ZodString;
|
|
227
|
+
missing: z.ZodOptional<z.ZodLiteral<true>>;
|
|
228
|
+
claimed: z.ZodOptional<z.ZodLiteral<true>>;
|
|
229
|
+
}, z.core.$loose>>>;
|
|
230
|
+
}, z.core.$loose>;
|
|
231
|
+
"tool.rejected": z.ZodObject<{
|
|
232
|
+
call_id: z.ZodString;
|
|
233
|
+
name: z.ZodString;
|
|
234
|
+
code: z.ZodEnum<{
|
|
235
|
+
invalid_path: "invalid_path";
|
|
236
|
+
not_allowed: "not_allowed";
|
|
237
|
+
outside_workspace: "outside_workspace";
|
|
238
|
+
reserved_path: "reserved_path";
|
|
239
|
+
schema_mismatch: "schema_mismatch";
|
|
240
|
+
unknown_tool: "unknown_tool";
|
|
241
|
+
}>;
|
|
242
|
+
reason: z.ZodString;
|
|
243
|
+
}, z.core.$loose>;
|
|
244
|
+
"human.input_requested": z.ZodObject<{
|
|
245
|
+
call_id: z.ZodString;
|
|
246
|
+
question: z.ZodString;
|
|
247
|
+
}, z.core.$loose>;
|
|
248
|
+
"human.input_provided": z.ZodObject<{
|
|
249
|
+
call_id: z.ZodString;
|
|
250
|
+
answer: z.ZodString;
|
|
251
|
+
}, z.core.$loose>;
|
|
252
|
+
"human.message": z.ZodObject<{
|
|
253
|
+
text: z.ZodString;
|
|
254
|
+
}, z.core.$loose>;
|
|
255
|
+
"usage.recorded": z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
256
|
+
kind: z.ZodLiteral<"model_inference">;
|
|
257
|
+
provider: z.ZodString;
|
|
258
|
+
model: z.ZodString;
|
|
259
|
+
usage: z.ZodObject<{
|
|
260
|
+
input_tokens: z.ZodInt;
|
|
261
|
+
output_tokens: z.ZodInt;
|
|
262
|
+
cached_input_tokens: z.ZodOptional<z.ZodInt>;
|
|
263
|
+
cache_write_tokens: z.ZodOptional<z.ZodInt>;
|
|
264
|
+
reasoning_tokens: z.ZodOptional<z.ZodInt>;
|
|
265
|
+
}, z.core.$loose>;
|
|
266
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
267
|
+
kind: z.ZodLiteral<"tool_execution">;
|
|
268
|
+
provider: z.ZodString;
|
|
269
|
+
usage: z.ZodObject<{
|
|
270
|
+
duration_ms: z.ZodInt;
|
|
271
|
+
}, z.core.$loose>;
|
|
272
|
+
}, z.core.$loose>], "kind">;
|
|
273
|
+
"evidence.recorded": z.ZodObject<{
|
|
274
|
+
claim: z.ZodString;
|
|
275
|
+
refs: z.ZodArray<z.ZodString>;
|
|
276
|
+
artifacts: z.ZodArray<z.ZodObject<{
|
|
277
|
+
path: z.ZodString;
|
|
278
|
+
sha256: z.ZodString;
|
|
279
|
+
missing: z.ZodOptional<z.ZodLiteral<true>>;
|
|
280
|
+
claimed: z.ZodOptional<z.ZodLiteral<true>>;
|
|
281
|
+
}, z.core.$loose>>;
|
|
282
|
+
}, z.core.$loose>;
|
|
283
|
+
"work.completed": z.ZodObject<{
|
|
284
|
+
summary: z.ZodString;
|
|
285
|
+
}, z.core.$loose>;
|
|
286
|
+
"work.failed": z.ZodObject<{
|
|
287
|
+
reason: z.ZodString;
|
|
288
|
+
detail: z.ZodString;
|
|
289
|
+
}, z.core.$loose>;
|
|
290
|
+
};
|
|
291
|
+
export declare const EventFileSchema: z.ZodObject<{
|
|
292
|
+
v: z.ZodLiteral<1>;
|
|
293
|
+
id: z.ZodString;
|
|
294
|
+
work_id: z.ZodString;
|
|
295
|
+
seq: z.ZodInt;
|
|
296
|
+
type: z.ZodString;
|
|
297
|
+
occurred_at: z.ZodISODateTime;
|
|
298
|
+
recorded_at: z.ZodISODateTime;
|
|
299
|
+
payload: z.ZodUnknown;
|
|
300
|
+
}, z.core.$strict>;
|
|
301
|
+
export type EventFile = z.infer<typeof EventFileSchema>;
|
|
302
|
+
export declare function eventToFile(event: AnyEvent): EventFile;
|
|
303
|
+
/**
|
|
304
|
+
* Canonical JSON form: object keys sorted recursively so that equal data is
|
|
305
|
+
* written as equal bytes. Inside the free-form fields (`input`, `data`, `value`,
|
|
306
|
+
* `raw`) `undefined` becomes `null`, because JSON has no `undefined` and a
|
|
307
|
+
* dropped key would make the line unreadable.
|
|
308
|
+
*/
|
|
309
|
+
export declare function canonical(value: unknown, insideData?: boolean, seen?: WeakSet<object>): unknown;
|
|
310
|
+
export declare function eventFromFile(input: unknown): AnyEvent;
|
|
311
|
+
export {};
|