@ccmsg/protocol 1.14.0 → 1.15.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ccmsg/protocol",
3
- "version": "1.14.0",
3
+ "version": "1.15.0",
4
4
  "description": "Wire contract (schema + types + op attribute table) shared by the ccmsg daemon and web UI",
5
5
  "license": "MIT",
6
6
  "author": "kawaz",
package/src/attributes.ts CHANGED
@@ -179,7 +179,7 @@ export const OP_ATTRIBUTES = {
179
179
  roles: SESSION_ONLY,
180
180
  needs_hello: true,
181
181
  locality: "cluster",
182
- errors: [],
182
+ errors: ["rate_limited"],
183
183
  },
184
184
  say_mark_read: {
185
185
  plane: "messaging",
@@ -193,7 +193,7 @@ export const OP_ATTRIBUTES = {
193
193
  roles: AGENT_AND_USER,
194
194
  needs_hello: true,
195
195
  locality: "cluster",
196
- errors: [],
196
+ errors: ["rate_limited"],
197
197
  },
198
198
 
199
199
  // --- control: session observation and operation (10) ---
@@ -129,12 +129,21 @@ const USE_FIELDS = {
129
129
  role: Type.Literal("use"),
130
130
  /** The result's id, once there is one. */
131
131
  result_item: Type.Optional(TranscriptItemId),
132
+ /** The harness's own key for this call, which the result names back. */
133
+ tool_use_id: Type.String(),
132
134
  };
133
135
 
134
136
  const RESULT_FIELDS = {
135
137
  role: Type.Literal("result"),
136
- /** The call this answers. Always known: a result exists because a call did. */
137
- parent_item: TranscriptItemId,
138
+ /** The call this answers, when the reader saw it. A read that begins in the
139
+ * middle of a file — a topic's seed, a transcript resumed from another file —
140
+ * meets results whose call is behind where it started, and an id it never
141
+ * read is one it cannot name. */
142
+ parent_item: Type.Optional(TranscriptItemId),
143
+ /** The harness's key for the call this answers, which the record carries
144
+ * whether or not the call was read. A reader that has no `parent_item` joins
145
+ * on this against the `tool_use_id` of the calls it holds. */
146
+ parent_tool_use_id: Type.String(),
138
147
  };
139
148
 
140
149
  function item<T extends TSchema, F extends Record<string, TSchema>>(type: T, fields: F) {
@@ -259,7 +268,6 @@ const ToolType = Type.String({ pattern: "^tool:[A-Za-z0-9_.-]+$" });
259
268
  function toolUse<N extends string, F extends Record<string, TSchema>>(name: N, fields: F) {
260
269
  return item(Type.Literal(`tool:${name}` as const), {
261
270
  ...USE_FIELDS,
262
- tool_use_id: Type.String(),
263
271
  ...fields,
264
272
  });
265
273
  }
@@ -267,7 +275,6 @@ function toolUse<N extends string, F extends Record<string, TSchema>>(name: N, f
267
275
  function toolResult<N extends string, F extends Record<string, TSchema>>(name: N, fields: F) {
268
276
  return item(Type.Literal(`tool:${name}` as const), {
269
277
  ...RESULT_FIELDS,
270
- tool_use_id: Type.String(),
271
278
  ...fields,
272
279
  });
273
280
  }
@@ -280,12 +287,10 @@ const OptCount = Type.Optional(Type.Integer({ minimum: 0 }));
280
287
  * to decide whether it is kept. */
281
288
  const ToolUseGeneric = item(ToolType, {
282
289
  ...USE_FIELDS,
283
- tool_use_id: Type.String(),
284
290
  input: Type.Record(Type.String(), Type.Unknown()),
285
291
  });
286
292
  const ToolResultGeneric = item(ToolType, {
287
293
  ...RESULT_FIELDS,
288
- tool_use_id: Type.String(),
289
294
  result: Type.Record(Type.String(), Type.Unknown()),
290
295
  });
291
296
 
@@ -62,10 +62,13 @@ export const TranscriptReadResponse = response("transcript_read", TranscriptRead
62
62
  *
63
63
  * The range is cut the way a dump's is — an instant or a record on either side
64
64
  * — and which end of it a limit keeps follows from which bound was given. A
65
- * lower bound reads forward from it and `next` names the continuation; an upper
66
- * bound alone reads the range's last items and `prev` names the continuation
67
- * backwards, which is how a client that draws the newest items first walks back
68
- * through a transcript it never has to read whole. The role decides how much is
65
+ * lower bound reads forward from it and `next` names the continuation;
66
+ * otherwise the read answers the range's last items and `prev` names the
67
+ * continuation backwards, which is how a client that draws the newest items
68
+ * first walks back through a transcript it never has to read whole. Asking
69
+ * with no bound at all is the ordinary first read, and it answers the tail, as
70
+ * the raw read with no `before` does; a client that wants the transcript from
71
+ * its beginning says so with `since_at: 0`. The role decides how much is
69
72
  * visible, as it does for the raw read. */
70
73
  export const TranscriptItemsReadArgs = Type.Object({
71
74
  sid: Sid,
@@ -90,8 +93,8 @@ export const TranscriptItemsReadArgs = Type.Object({
90
93
  * but the attachments, as a dump's absent selection does. */
91
94
  types: Type.Optional(Type.Array(TranscriptItemSelector)),
92
95
  /** How many items to answer with, taken from the range's start when a lower
93
- * bound was given and from its end when only an upper one was; the instance
94
- * narrows this to its own limit. */
96
+ * bound was given and from its end otherwise; the instance narrows this to
97
+ * its own limit. */
95
98
  limit: Type.Optional(Type.Integer({ minimum: 1 })),
96
99
  });
97
100
  export type TranscriptItemsReadArgs = Static<typeof TranscriptItemsReadArgs>;
package/src/errors.ts CHANGED
@@ -18,6 +18,15 @@ export const ERROR_CODES = [
18
18
  * arguments that were never the problem. Whether retrying helps is not stated;
19
19
  * `msg` is the only thing that says more. */
20
20
  "internal_error",
21
+ // --- backpressure ---
22
+ /** The call was well-formed and allowed, and the instance is not taking it
23
+ * just now: what it would be queued behind has reached the limit the sender
24
+ * keeps to. Apart from `internal_error` because nothing failed and the
25
+ * arguments are not what to re-read — the same call sent again once the
26
+ * reader has caught up is the one that goes through. Which ops answer it is
27
+ * in their `errors`, since only an op that queues for a reader has a queue to
28
+ * fill. */
29
+ "rate_limited",
21
30
  // --- rule-derived (op attribute table §0) ---
22
31
  /** The connection's role is outside the op's `roles`. Argument problems stay
23
32
  * on `invalid_args` / `bad_request`. */
@@ -261,8 +261,8 @@ export const TRANSCRIPT_ITEMS: Static<typeof TranscriptItem>[] = [
261
261
  type: "tool:Bash",
262
262
  at: FIXTURE_NOW - 3_399_000,
263
263
  role: "result",
264
- tool_use_id: "toolu_01Ne9BDS",
265
264
  parent_item: "f10b6d43:1",
265
+ parent_tool_use_id: "toolu_01Ne9BDS",
266
266
  stdout: "1174 assistant\n753 user\n",
267
267
  interrupted: false,
268
268
  },
@@ -274,6 +274,7 @@ export const TRANSCRIPT_ITEMS: Static<typeof TranscriptItem>[] = [
274
274
  at: FIXTURE_NOW - 3_300_000,
275
275
  role: "use",
276
276
  result_item: "c2d80f16:0",
277
+ tool_use_id: "toolu_01Rk4WQm",
277
278
  prompt: "docs/design/dump-kinds.md を書き直す",
278
279
  agent_id: "a471372f2",
279
280
  subagent_type: "opus5-worker-high",