@celestea/core 2.7.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.
Files changed (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +95 -0
  3. package/contracts/data-files/checkpoint.schema.json +111 -0
  4. package/contracts/data-files/cli-main-jsonl-precompact.schema.json +27 -0
  5. package/contracts/data-files/cli-main-jsonl.schema.json +22 -0
  6. package/contracts/data-files/fallbacks.schema.json +71 -0
  7. package/contracts/data-files/index.json +124 -0
  8. package/contracts/data-files/pricing.schema.json +65 -0
  9. package/contracts/data-files/prompts.schema.json +130 -0
  10. package/contracts/data-files/providers.schema.json +177 -0
  11. package/contracts/data-files/registry-tsv.schema.json +74 -0
  12. package/contracts/data-files/session.schema.json +51 -0
  13. package/contracts/data-files/usage-ledger.schema.json +112 -0
  14. package/contracts/data-files/workspaces.schema.json +63 -0
  15. package/contracts/endpoints.json +4390 -0
  16. package/contracts/probe-evidence.json +219 -0
  17. package/contracts/route-table.snapshot.json +377 -0
  18. package/contracts/scope-hash-vectors.json +273 -0
  19. package/contracts/session-event.schema.json +441 -0
  20. package/contracts/sse-events.json +202 -0
  21. package/contracts/tools.json +730 -0
  22. package/dist/agent.d.ts +65 -0
  23. package/dist/agent.js +36 -0
  24. package/dist/celestea-home.d.ts +63 -0
  25. package/dist/celestea-home.js +96 -0
  26. package/dist/celestea-sources.d.ts +53 -0
  27. package/dist/celestea-sources.js +61 -0
  28. package/dist/context.d.ts +33 -0
  29. package/dist/context.js +55 -0
  30. package/dist/contracts/index.d.ts +234 -0
  31. package/dist/contracts/index.js +159 -0
  32. package/dist/errors.d.ts +16 -0
  33. package/dist/errors.js +22 -0
  34. package/dist/event-bus.d.ts +60 -0
  35. package/dist/event-bus.js +100 -0
  36. package/dist/index.d.ts +66 -0
  37. package/dist/index.js +66 -0
  38. package/dist/injection.d.ts +61 -0
  39. package/dist/injection.js +27 -0
  40. package/dist/json.d.ts +34 -0
  41. package/dist/json.js +127 -0
  42. package/dist/llm.d.ts +34 -0
  43. package/dist/llm.js +41 -0
  44. package/dist/memory.d.ts +72 -0
  45. package/dist/memory.js +123 -0
  46. package/dist/message.d.ts +189 -0
  47. package/dist/message.js +252 -0
  48. package/dist/plugin.d.ts +38 -0
  49. package/dist/plugin.js +49 -0
  50. package/dist/projection.d.ts +67 -0
  51. package/dist/projection.js +168 -0
  52. package/dist/question.d.ts +154 -0
  53. package/dist/question.js +82 -0
  54. package/dist/redact.d.ts +40 -0
  55. package/dist/redact.js +185 -0
  56. package/dist/repo.d.ts +14 -0
  57. package/dist/repo.js +87 -0
  58. package/dist/sandbox.d.ts +182 -0
  59. package/dist/sandbox.js +78 -0
  60. package/dist/session-event.d.ts +57 -0
  61. package/dist/session-event.js +425 -0
  62. package/dist/session-log.d.ts +71 -0
  63. package/dist/session-log.js +66 -0
  64. package/dist/skill-catalog.d.ts +29 -0
  65. package/dist/skill-catalog.js +52 -0
  66. package/dist/skills.d.ts +116 -0
  67. package/dist/skills.js +273 -0
  68. package/dist/sse-bus.d.ts +40 -0
  69. package/dist/sse-bus.js +105 -0
  70. package/dist/stream.d.ts +115 -0
  71. package/dist/stream.js +52 -0
  72. package/dist/tool-surface.d.ts +45 -0
  73. package/dist/tool-surface.js +98 -0
  74. package/dist/tool.d.ts +77 -0
  75. package/dist/tool.js +15 -0
  76. package/dist/turn-id.d.ts +37 -0
  77. package/dist/turn-id.js +76 -0
  78. package/dist/types.d.ts +396 -0
  79. package/dist/types.js +58 -0
  80. package/package.json +27 -0
@@ -0,0 +1,396 @@
1
+ /**
2
+ * Core shared types for the Celestea TS rewrite.
3
+ *
4
+ * These mirror the frozen contracts 1:1:
5
+ * - SessionEvent / TurnOutcome : celestea_harness/crates/core/src/session_log.rs
6
+ * - SSE envelope + LoopEvent : celestea_studio/src/main.rs:640-732
7
+ * - Studio message projection : celestea_studio/src/api.rs:94-135
8
+ *
9
+ * Field names are contract, not style: do not rename anything here.
10
+ */
11
+ import type { ImageRef } from "./message.js";
12
+ /** The 5 real terminal states of a turn (never collapse these). */
13
+ export type TurnOutcome = "completed" | "cancelled" | {
14
+ error: {
15
+ kind: "generate" | "stream";
16
+ message: string;
17
+ };
18
+ } | "step_limit" | "interrupted";
19
+ export declare const TURN_OUTCOMES: readonly string[];
20
+ export interface TurnStartEvent {
21
+ type: "turn_start";
22
+ id: string;
23
+ }
24
+ export interface TurnEndEvent {
25
+ type: "turn_end";
26
+ id: string;
27
+ /** Legacy rows omit it and deserialize as "completed". */
28
+ outcome?: TurnOutcome;
29
+ }
30
+ export interface UserMessageEvent {
31
+ type: "user_message";
32
+ text: string;
33
+ /**
34
+ * W804: content-addressed image references attached to this message. Omitted
35
+ * entirely when there are none (serde style), so every pre-W804 row is
36
+ * byte-identical; the bytes live in the session's attachments/ directory and
37
+ * NEVER in the log.
38
+ */
39
+ attachments?: ImageRef[];
40
+ /**
41
+ * W888: WHERE this user-role row came from. Absent = 'user' (a real typed
42
+ * input), so every pre-W888 log row is byte-identical and reads as a user
43
+ * bubble. A non-'user' origin lets the transcript render an injected block
44
+ * (skill catalog / memory / receipt / steering / compaction) as an INBOX row,
45
+ * visually distinct from something the human actually said.
46
+ *
47
+ * Omitted when it is 'user' (serde style): the common case keeps the old bytes.
48
+ */
49
+ origin?: SessionEventOrigin;
50
+ }
51
+ /** W888: the closed set of `user_message` origins. */
52
+ export type SessionEventOrigin = "user" | "skill" | "memory" | "receipt" | "steering" | "compact";
53
+ export declare const SESSION_EVENT_ORIGINS: readonly string[];
54
+ export interface AssistantMessageEvent {
55
+ type: "assistant_message";
56
+ text: string;
57
+ }
58
+ export interface ThinkingDeltaEvent {
59
+ type: "thinking_delta";
60
+ text: string;
61
+ }
62
+ export interface ToolCallEvent {
63
+ type: "tool_call";
64
+ id: string;
65
+ name: string;
66
+ args: unknown;
67
+ /** W255 run_code sub-call: present only for nested rows. */
68
+ parent_id?: string;
69
+ }
70
+ /**
71
+ * W855 (B6): how the MODEL-VISIBLE face of a tool result is derived from the
72
+ * log's ORIGINAL `value` at read time. The session log stores the original; the
73
+ * projection (`projection.ts`) applies this descriptor. Keeping it on the row is
74
+ * what makes a replay reproduce the live model context byte for byte (the
75
+ * retention decision is a per-step budget outcome, not a pure function of the
76
+ * value).
77
+ */
78
+ export type ToolResultSurface = {
79
+ /** Retention replaced an oversized result with a bounded head/tail window. */
80
+ kind: "omitted";
81
+ omitted_bytes: number;
82
+ total_bytes: number;
83
+ locator: string;
84
+ retrieval_hint: string;
85
+ head_bytes: number;
86
+ tail_bytes: number;
87
+ } | {
88
+ /** The tool itself truncated the result and authored a retrieval note. */
89
+ kind: "truncation";
90
+ note: string;
91
+ };
92
+ export interface ToolResultEvent {
93
+ type: "tool_result";
94
+ id: string;
95
+ value: unknown;
96
+ error: string | null;
97
+ /** W255 run_code sub-call: present only for nested rows. */
98
+ parent_id?: string;
99
+ /** W855 (B6): the model-face descriptor; absent = project `value` as-is. */
100
+ surface?: ToolResultSurface;
101
+ }
102
+ /**
103
+ * W783 §7: the model ASKED the user something. A host-side audit row (the engine
104
+ * never writes one) recording the request while the turn is parked, so a client
105
+ * that reconnects can rebuild the card and a replay can see what was asked.
106
+ */
107
+ export interface UserQuestionEvent {
108
+ type: "user_question";
109
+ /** Request id (`q-<n>`), echoed by the matching `user_answer` row. */
110
+ id: string;
111
+ /** The question batch as the model asked it. */
112
+ questions: unknown[];
113
+ /**
114
+ * Absolute deadline in ms, judged at READ time (§6.1) — so a replay still
115
+ * knows whether the question had expired, with no timer involved.
116
+ */
117
+ expires_at?: number;
118
+ /** The resolved maximum wait in ms. */
119
+ timeout_ms?: number;
120
+ }
121
+ /**
122
+ * W783 §7: the question was answered (or expired). `answers` holds the same
123
+ * items the tool returned, with `selected` as option LABELS.
124
+ */
125
+ export interface UserAnswerEvent {
126
+ type: "user_answer";
127
+ /** The request id this row answers. */
128
+ id: string;
129
+ answers: unknown[];
130
+ /** `true` = the deadline expired and no answer exists (§6.3). */
131
+ timed_out?: boolean;
132
+ }
133
+ export type SessionEvent = TurnStartEvent | TurnEndEvent | UserMessageEvent | AssistantMessageEvent | ThinkingDeltaEvent | ToolCallEvent | ToolResultEvent | UserQuestionEvent | UserAnswerEvent;
134
+ export declare const SESSION_EVENT_TYPES: readonly ["turn_start", "turn_end", "user_message", "assistant_message", "thinking_delta", "tool_call", "tool_result", "user_question", "user_answer"];
135
+ export type SessionEventType = (typeof SESSION_EVENT_TYPES)[number];
136
+ export interface UserMessageOut {
137
+ role: "user";
138
+ content: string;
139
+ /**
140
+ * W804: the attachments of this user message (references only). Omitted when
141
+ * there are none, so every existing golden message stays byte-identical.
142
+ */
143
+ attachments?: ImageRef[];
144
+ }
145
+ /**
146
+ * W888: an injected user-role row projected for the transcript — NOT something
147
+ * the human typed. `kind` is the origin ('skill' | 'memory' | 'receipt' |
148
+ * 'steering' | 'compact'); `source` is the human-readable label the UI shows.
149
+ * There is no `content` field here because the wire shape reuses `content` at
150
+ * the projection site (kept in [StudioMessage] as the shared discriminator).
151
+ */
152
+ export interface InboxMessageOut {
153
+ role: "inbox";
154
+ kind: SessionEventOrigin;
155
+ content: string;
156
+ /** Human-readable origin label (e.g. '技能目录', '记忆 · 每轮注入', '回执 · W1'). */
157
+ source: string;
158
+ attachments?: ImageRef[];
159
+ }
160
+ export interface AssistantMessageOut {
161
+ role: "assistant";
162
+ content: string;
163
+ }
164
+ export interface ThinkingMessageOut {
165
+ role: "thinking";
166
+ content: string;
167
+ }
168
+ export interface ToolCallMessageOut {
169
+ role: "tool";
170
+ kind: "call";
171
+ tool_call_id: string;
172
+ tool_name: string;
173
+ tool_args: unknown;
174
+ tool_parent_id?: string;
175
+ }
176
+ export interface ToolResultMessageOut {
177
+ role: "tool";
178
+ kind: "result";
179
+ tool_call_id: string;
180
+ /** W855 (B6): the bounded/annotated model face when the row carries a `surface`. */
181
+ tool_value: unknown;
182
+ tool_error: string | null;
183
+ tool_parent_id?: string;
184
+ tool_surface?: ToolResultSurface;
185
+ }
186
+ /**
187
+ * W783 §7: a question the model asked, as the transcript surface shows it.
188
+ * `content` carries the raw batch the tool received.
189
+ */
190
+ export interface QuestionAskedMessageOut {
191
+ role: "question";
192
+ kind: "question";
193
+ /** Request id (`q-<n>`), matching the `user_answer` row. */
194
+ question_id: string;
195
+ content: unknown;
196
+ /** Absolute deadline in ms (absent on a legacy/hand-written row). */
197
+ question_expires_at?: number;
198
+ }
199
+ /**
200
+ * W783 §7: the answer to a question (or the fact that it expired). `content`
201
+ * carries the answer items, whose `selected` entries are option LABELS.
202
+ */
203
+ export interface QuestionAnsweredMessageOut {
204
+ role: "question";
205
+ kind: "answer";
206
+ question_id: string;
207
+ content: unknown;
208
+ /** `true` = the deadline expired; nothing was chosen on the model's behalf. */
209
+ question_timed_out?: boolean;
210
+ }
211
+ export type StudioMessage = UserMessageOut | InboxMessageOut | AssistantMessageOut | ThinkingMessageOut | ToolCallMessageOut | ToolResultMessageOut | QuestionAskedMessageOut | QuestionAnsweredMessageOut;
212
+ export declare const SSE_EVENT_NAMES: readonly ["text", "thinking", "tool", "tool_result", "turn_end", "done", "status", "compact", "question"];
213
+ export type SseEventName = (typeof SSE_EVENT_NAMES)[number];
214
+ /**
215
+ * `data:` field of every SSE frame.
216
+ *
217
+ * W513 extension (pure addition): `v` is the envelope version (2 = per-session
218
+ * envelope; a missing `v` is a legacy 0 envelope) and `session` names the
219
+ * session the frame belongs to (`null` = process-level frame, e.g. `lagged`).
220
+ * `turn` is the SESSION-local turn number, `seq` stays process-global monotonic
221
+ * and `payload` is unchanged.
222
+ */
223
+ export interface SseEnvelope<P = unknown> {
224
+ v: number;
225
+ session: string | null;
226
+ turn: number;
227
+ seq: number;
228
+ payload: P;
229
+ }
230
+ export declare const STATUS_PHASES: readonly ["start", "progress", "completed", "cancelled", "error", "step_limit", "interrupted", "lagged"];
231
+ export type StatusPhase = (typeof STATUS_PHASES)[number];
232
+ export interface Statusline {
233
+ model: string;
234
+ reasoning_effort: string | null;
235
+ steps: number;
236
+ /**
237
+ * W218/W754/W763 throughput estimate, in CHARACTERS per second (the frozen
238
+ * field name is historical; the UI shows it as an approximate ~1:1 token rate).
239
+ * The mean over "active" intervals only — no-flow breaks (> `GAP_MS` = 1s
240
+ * between deltas: long tool calls, stalls, the idle tail of a finished turn)
241
+ * never enter the denominator. It is the responsive 5s window rate while that
242
+ * window still carries output, and the whole TURN's active-interval mean once
243
+ * the window empties, so it stays a stable positive number after a stall or
244
+ * after the turn ends. 0 means exactly one thing: this turn has produced no
245
+ * text/thinking delta yet (TTFT). Reset by the next turn.
246
+ */
247
+ tokens_per_sec: number;
248
+ context_usage: {
249
+ used: number;
250
+ window: number;
251
+ ratio: number;
252
+ /** W755: `used` is the visible-surface ESTIMATE, not a real provider sample. */
253
+ estimated: boolean;
254
+ /**
255
+ * W755 source vocabulary:
256
+ * - `usage_prompt_tokens` the REAL prompt of a provider usage frame;
257
+ * - `assembled_estimate` the token estimate of the loop's own next request
258
+ * (system + trimmed history + tool schemas);
259
+ * - `none` nothing measurable -> the UI shows "unknown";
260
+ * - `session_event_chars` RETIRED in v2.5.0 (the session log's CHARACTER
261
+ * count was divided by a TOKEN window). Kept in the
262
+ * union so a consumer can still recognise a payload
263
+ * from an older build; never emitted any more.
264
+ */
265
+ method: "usage_prompt_tokens" | "session_event_chars" | "assembled_estimate" | "none";
266
+ /**
267
+ * W755 (Fix B): true when `used` carries the model-visible growth measured
268
+ * after the prompt sample — i.e. it answers for the NEXT request rather than
269
+ * the last one (DSH `projectedTokens`). Distinct from `estimated`.
270
+ */
271
+ projected: boolean;
272
+ /**
273
+ * W755 (Fix C): where `window` came from. `ratio` is a real measurement only
274
+ * for `profile`; `fallback` (no declared capacity -> the 1,000,000 display
275
+ * default applies) and `unknown` both report `window: 0, ratio: 0`.
276
+ */
277
+ window_source: "profile" | "fallback" | "unknown";
278
+ };
279
+ usage: UsageBlock & {
280
+ total: UsageBlock;
281
+ };
282
+ }
283
+ export interface UsageBlock {
284
+ prompt_tokens: number;
285
+ completion_tokens: number;
286
+ total_tokens: number;
287
+ cache_read: number;
288
+ cache_hit_ratio: number;
289
+ reasoning_tokens: number;
290
+ }
291
+ /** Engine loop events, mapped 1:1 onto SSE names by loop_event_to_json. */
292
+ export type LoopEvent = {
293
+ kind: "text";
294
+ delta: string;
295
+ } | {
296
+ kind: "thinking";
297
+ delta: string;
298
+ } | {
299
+ kind: "tool_call";
300
+ id: string;
301
+ name: string;
302
+ args: unknown;
303
+ } | {
304
+ kind: "tool_result";
305
+ callId: string;
306
+ ok: boolean;
307
+ value: unknown;
308
+ render: unknown;
309
+ error: string | null;
310
+ decision: "allow" | "deny" | "ask" | null;
311
+ } | {
312
+ kind: "turn_end";
313
+ outcome: TurnOutcome;
314
+ } | {
315
+ kind: "done";
316
+ text: string;
317
+ tool_calls: Array<{
318
+ id: string;
319
+ name: string;
320
+ args: unknown;
321
+ }>;
322
+ };
323
+ export interface ErrorEnvelope {
324
+ ok: false;
325
+ error: string;
326
+ }
327
+ export interface OkEnvelope {
328
+ ok: true;
329
+ }
330
+ export interface ToolSpec {
331
+ name: string;
332
+ description: string;
333
+ parameters: Record<string, unknown>;
334
+ }
335
+ export type ToolDecision = {
336
+ kind: "allow";
337
+ } | {
338
+ kind: "deny";
339
+ reason: string;
340
+ } | {
341
+ kind: "ask";
342
+ reason: string;
343
+ };
344
+ export interface ProviderModelPublic {
345
+ id: string;
346
+ name: string;
347
+ reasoning_efforts: string[];
348
+ context_window: number | null;
349
+ max_output_tokens: number | null;
350
+ }
351
+ /** NOTE: `api_key` is intentionally absent from this type. */
352
+ export interface ProviderPublicView {
353
+ id: string;
354
+ name: string;
355
+ note: string;
356
+ base_url: string;
357
+ request_format: "chat_completions" | "responses" | "anthropic_messages";
358
+ models: ProviderModelPublic[];
359
+ is_default: boolean;
360
+ has_key: boolean;
361
+ }
362
+ export interface ProvidersView {
363
+ providers: ProviderPublicView[];
364
+ default_model: string | null;
365
+ }
366
+ export interface WorkspaceView {
367
+ name: string;
368
+ path: string;
369
+ sessions: number;
370
+ }
371
+ export interface WorkspacesView {
372
+ workspaces: WorkspaceView[];
373
+ active_session: string | null;
374
+ }
375
+ export interface SessionSummary {
376
+ id: string;
377
+ workspace: string;
378
+ title: string;
379
+ model: string | null;
380
+ size: number;
381
+ modified: number;
382
+ active: boolean;
383
+ kind?: "worker";
384
+ }
385
+ export interface SessionsView {
386
+ sessions: SessionSummary[];
387
+ active_session: string | null;
388
+ }
389
+ export declare const WORKER_STATUSES: readonly ["RUNNING", "DONE", "FAILED", "STOPPED"];
390
+ export type WorkerStatus = (typeof WORKER_STATUSES)[number];
391
+ export interface WorkerEntry {
392
+ wid: string;
393
+ started_at: string;
394
+ status: WorkerStatus;
395
+ extra: string;
396
+ }
package/dist/types.js ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Core shared types for the Celestea TS rewrite.
3
+ *
4
+ * These mirror the frozen contracts 1:1:
5
+ * - SessionEvent / TurnOutcome : celestea_harness/crates/core/src/session_log.rs
6
+ * - SSE envelope + LoopEvent : celestea_studio/src/main.rs:640-732
7
+ * - Studio message projection : celestea_studio/src/api.rs:94-135
8
+ *
9
+ * Field names are contract, not style: do not rename anything here.
10
+ */
11
+ export const TURN_OUTCOMES = [
12
+ "completed",
13
+ "cancelled",
14
+ "error",
15
+ "step_limit",
16
+ "interrupted",
17
+ ];
18
+ export const SESSION_EVENT_ORIGINS = ["user", "skill", "memory", "receipt", "steering", "compact"];
19
+ export const SESSION_EVENT_TYPES = [
20
+ "turn_start",
21
+ "turn_end",
22
+ "user_message",
23
+ "assistant_message",
24
+ "thinking_delta",
25
+ "tool_call",
26
+ "tool_result",
27
+ "user_question",
28
+ "user_answer",
29
+ ];
30
+ // ---------------------------------------------------------------------------
31
+ // SSE (GET /api/events)
32
+ // ---------------------------------------------------------------------------
33
+ export const SSE_EVENT_NAMES = [
34
+ "text",
35
+ "thinking",
36
+ "tool",
37
+ "tool_result",
38
+ "turn_end",
39
+ "done",
40
+ "status",
41
+ "compact",
42
+ // W783: the model asked the user something and the turn is PARKED on it.
43
+ "question",
44
+ ];
45
+ export const STATUS_PHASES = [
46
+ "start",
47
+ "progress",
48
+ "completed",
49
+ "cancelled",
50
+ "error",
51
+ "step_limit",
52
+ "interrupted",
53
+ "lagged",
54
+ ];
55
+ // ---------------------------------------------------------------------------
56
+ // Workers (registry.tsv)
57
+ // ---------------------------------------------------------------------------
58
+ export const WORKER_STATUSES = ["RUNNING", "DONE", "FAILED", "STOPPED"];
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@celestea/core",
3
+ "version": "2.7.1",
4
+ "private": false,
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "default": "./dist/index.js"
10
+ }
11
+ },
12
+ "dependencies": {},
13
+ "license": "MIT",
14
+ "files": [
15
+ "dist",
16
+ "contracts"
17
+ ],
18
+ "main": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "scripts": {
24
+ "typecheck": "tsc --noEmit -p tsconfig.json",
25
+ "build": "tsc -p tsconfig.build.json && node ../../scripts/build-contracts.mjs"
26
+ }
27
+ }