@crossworks/client-types 0.232.133 → 0.232.142
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/package.json +1 -1
- package/src/dto/agent-graph.ts +229 -0
- package/src/dto/agents.ts +190 -0
- package/src/dto/comms.ts +114 -0
- package/src/dto/heartbeats.ts +60 -0
- package/src/dto/recall.ts +21 -0
- package/src/dto/rows.ts +882 -0
- package/src/dto/turns.ts +192 -0
- package/src/dto/views.ts +936 -0
- package/src/index.ts +15 -2534
- package/src/model-pools-data.json +2194 -0
- package/src/model-pools-data.ts +10 -2194
- package/src/model-pools-template.test.ts +77 -0
package/src/dto/turns.ts
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mantle/client-types · turns
|
|
3
|
+
*
|
|
4
|
+
* Live turn streaming and the ask_human questionnaire the runner queues raise.
|
|
5
|
+
*
|
|
6
|
+
* Split out of the 2548-line index.ts on 2026-09-02 (audit, tier 3) with the
|
|
7
|
+
* contents unchanged. index.ts re-exports every one of these, so the package's
|
|
8
|
+
* public surface is byte-identical — only the file a symbol lives in moved.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ── Live turn streaming ─────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The cross-client contract for live "what the agent is doing" updates during a
|
|
15
|
+
* turn — consumed identically by the web client and the Flutter companion (see
|
|
16
|
+
* `docs/live-turn-streaming.md`). One event stream unifies coarse status, tool
|
|
17
|
+
* activity, reasoning, and token deltas.
|
|
18
|
+
*
|
|
19
|
+
* This is the wire shape ONLY (zero-runtime, per this package's invariant): the
|
|
20
|
+
* server-side channel + publisher + schema-version constant live in
|
|
21
|
+
* `@mantle/turn-stream`; the producer stamps `v`/`seq`/`round`.
|
|
22
|
+
*
|
|
23
|
+
* Evolution rule: new `type`s and new `data` fields are additive (non-breaking) —
|
|
24
|
+
* a client ignores a `type` it doesn't recognise. A breaking change to an
|
|
25
|
+
* existing event's shape bumps `v` (`TURN_EVENT_SCHEMA_VERSION`).
|
|
26
|
+
*/
|
|
27
|
+
export type TurnEventType =
|
|
28
|
+
| 'turn-start'
|
|
29
|
+
| 'status'
|
|
30
|
+
| 'tool-start'
|
|
31
|
+
| 'tool-end'
|
|
32
|
+
| 'reasoning-delta'
|
|
33
|
+
| 'text-delta'
|
|
34
|
+
| 'done'
|
|
35
|
+
| 'error';
|
|
36
|
+
|
|
37
|
+
/** A pending outbound message now exists; the client can bind UI to `turnId`. */
|
|
38
|
+
export interface TurnStartData {
|
|
39
|
+
agentSlug: string;
|
|
40
|
+
/** Resolved model id, when known at turn start (else null). */
|
|
41
|
+
model: string | null;
|
|
42
|
+
/** Durable `assistant_messages` id of the inbound (user) row, persisted before
|
|
43
|
+
* the model runs. Lets a client swap its optimistic user bubble for the
|
|
44
|
+
* canonical row without waiting on the POST. Optional (additive): a client
|
|
45
|
+
* that predates this field ignores it. */
|
|
46
|
+
inboundId?: string;
|
|
47
|
+
/** Durable `assistant_messages` id of the outbound (reply) row, inserted
|
|
48
|
+
* `pending` at turn start. This is the turn's authoritative reconciliation
|
|
49
|
+
* handle — the client binds the reply bubble to it and, on `done`, reads the
|
|
50
|
+
* final text from this row (vs. the advisory streamed buffer). Optional. */
|
|
51
|
+
outboundId?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** A short "what it's doing now" line ("Searching your brain…"). `kind` is an
|
|
55
|
+
* optional coarse bucket the UI can theme/iconify. `stepId` ties together the
|
|
56
|
+
* grounded line and its later narrated upgrade for the SAME step, so the client
|
|
57
|
+
* replaces the line in place rather than appending a duplicate. */
|
|
58
|
+
export interface TurnStatusData {
|
|
59
|
+
label: string;
|
|
60
|
+
kind?: string;
|
|
61
|
+
/** Stable id for the step this status describes. Two events sharing a stepId
|
|
62
|
+
* are the same step (grounded → narrated); the client upserts by it. */
|
|
63
|
+
stepId?: string;
|
|
64
|
+
/** Present (true) only on the narrator's rephrased line for a step — the warm
|
|
65
|
+
* first-person paragraph. Grounded lines omit it. Lets clients keep narrated
|
|
66
|
+
* text visible while later grounded lines tick past. */
|
|
67
|
+
narrated?: true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** A tool round began. `summary` is an optional one-line, secret-free preview. */
|
|
71
|
+
export interface TurnToolStartData {
|
|
72
|
+
name: string;
|
|
73
|
+
summary?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** A tool round finished (`ok=false` = it errored — the turn may still recover). */
|
|
77
|
+
export interface TurnToolEndData {
|
|
78
|
+
name: string;
|
|
79
|
+
ok: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** A chunk of the model's reasoning stream (raw; may be curated before display). */
|
|
83
|
+
export interface TurnReasoningDeltaData {
|
|
84
|
+
text: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** A chunk of the visible reply text. */
|
|
88
|
+
export interface TurnTextDeltaData {
|
|
89
|
+
text: string;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Terminal success. The client now reconciles against the durable message row;
|
|
93
|
+
* the streamed text is advisory, the DB row is authoritative. */
|
|
94
|
+
export interface TurnDoneData {
|
|
95
|
+
status: 'complete';
|
|
96
|
+
/** Real output-token total for the whole turn (summed across rounds). The
|
|
97
|
+
* client shows a streamed char-based estimate while the reply types out, then
|
|
98
|
+
* swaps it for this exact figure on `done`. Optional + additive: absent when
|
|
99
|
+
* no provider reported usage, or from a producer that predates the field. */
|
|
100
|
+
tokensOut?: number;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Terminal failure. */
|
|
104
|
+
export interface TurnErrorData {
|
|
105
|
+
status: 'failed';
|
|
106
|
+
message: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Fields every turn event carries. */
|
|
110
|
+
export interface TurnEventBase {
|
|
111
|
+
/** Schema version (`TURN_EVENT_SCHEMA_VERSION` at emit time). */
|
|
112
|
+
v: number;
|
|
113
|
+
/** Durable turn id = the outbound `assistant_messages` id. Stable for the turn. */
|
|
114
|
+
turnId: string;
|
|
115
|
+
/** Monotonic per-turn sequence — the SSE `id:` field and the resume cursor. */
|
|
116
|
+
seq: number;
|
|
117
|
+
/** Tool-loop round this event belongs to (0 = before the first round). */
|
|
118
|
+
round: number;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** One live turn event. Discriminated on `type`; `data` is the matching payload. */
|
|
122
|
+
export type TurnEvent =
|
|
123
|
+
| (TurnEventBase & { type: 'turn-start'; data: TurnStartData })
|
|
124
|
+
| (TurnEventBase & { type: 'status'; data: TurnStatusData })
|
|
125
|
+
| (TurnEventBase & { type: 'tool-start'; data: TurnToolStartData })
|
|
126
|
+
| (TurnEventBase & { type: 'tool-end'; data: TurnToolEndData })
|
|
127
|
+
| (TurnEventBase & { type: 'reasoning-delta'; data: TurnReasoningDeltaData })
|
|
128
|
+
| (TurnEventBase & { type: 'text-delta'; data: TurnTextDeltaData })
|
|
129
|
+
| (TurnEventBase & { type: 'done'; data: TurnDoneData })
|
|
130
|
+
| (TurnEventBase & { type: 'error'; data: TurnErrorData });
|
|
131
|
+
|
|
132
|
+
// ── ask_human questionnaire (runner queues) ───────────────────────────────────
|
|
133
|
+
// THE single source of truth for the questionnaire contract. The plan parser
|
|
134
|
+
// (@mantle/tools) validates against these caps, the answer path (@mantle/runs)
|
|
135
|
+
// re-checks submissions against them, and the client renders whatever they
|
|
136
|
+
// admit. They lived in three places once and immediately disagreed — the
|
|
137
|
+
// client's id fallback diverged from the server's, and the client had no
|
|
138
|
+
// question cap while the API capped answers at 4, so a 5-question form
|
|
139
|
+
// rendered fine and then 400'd on submit.
|
|
140
|
+
|
|
141
|
+
/** One selectable answer. `description` is the muted subtext on the chip. */
|
|
142
|
+
export interface AskHumanFormOption {
|
|
143
|
+
label: string;
|
|
144
|
+
description?: string;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** One sub-question of a questionnaire. `id` is the routing key answers are
|
|
148
|
+
* submitted under; `header` is the short chip shown beside the question. */
|
|
149
|
+
export interface AskHumanFormQuestion {
|
|
150
|
+
id: string;
|
|
151
|
+
header?: string;
|
|
152
|
+
question: string;
|
|
153
|
+
options: AskHumanFormOption[];
|
|
154
|
+
multi_select?: boolean;
|
|
155
|
+
/** Free-text escape. Defaults ON — a question whose options don't fit and
|
|
156
|
+
* offers no way to say so forces a wrong answer. */
|
|
157
|
+
allow_other?: boolean;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface AskHumanForm {
|
|
161
|
+
questions: AskHumanFormQuestion[];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** One answered sub-question, as submitted to `PATCH /api/pending/:id` and
|
|
165
|
+
* `pending_approve`. `question` is the form question's `id`. */
|
|
166
|
+
export interface AskHumanFormAnswer {
|
|
167
|
+
question: string;
|
|
168
|
+
selected: string[];
|
|
169
|
+
other?: string;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Caps on a questionnaire. These are a CONTRACT, not advice: every answer
|
|
174
|
+
* surface renders whatever the parser admits, so an unbounded form is an
|
|
175
|
+
* unanswerable screen — and a cap enforced on only one side is a 400 the
|
|
176
|
+
* operator can't act on.
|
|
177
|
+
*/
|
|
178
|
+
export const ASK_HUMAN_FORM_LIMITS = {
|
|
179
|
+
/** Ask more than this and the answers to the first few probably change what
|
|
180
|
+
* you still need to ask — use a later `ask_human` step. */
|
|
181
|
+
maxQuestions: 4,
|
|
182
|
+
maxOptions: 8,
|
|
183
|
+
/** A header renders as a chip, not a sentence. */
|
|
184
|
+
maxHeaderChars: 24,
|
|
185
|
+
maxQuestionChars: 300,
|
|
186
|
+
maxLabelChars: 80,
|
|
187
|
+
maxDescriptionChars: 200,
|
|
188
|
+
maxOtherChars: 2_000,
|
|
189
|
+
/** The form rides in `run_items.payload` AND the pending row's args, and
|
|
190
|
+
* both are read into prompts. */
|
|
191
|
+
maxFormJsonBytes: 8_000,
|
|
192
|
+
} as const;
|