@camox/api-contract 0.62.0 → 0.63.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/threads.d.ts CHANGED
@@ -10,6 +10,14 @@ import { Message } from "@earendil-works/pi-ai";
10
10
  * studio as they sent it (`editorTextOf`).
11
11
  */
12
12
  export declare const EDITOR_MESSAGE_ENTRY = "camox.editor-message";
13
+ /**
14
+ * The kind of the transcript entry recording a Connected Agent's message (ADR 0030), with its
15
+ * member and client as data (`connectedAgentMessageDataSchema`). The model reads it as a user
16
+ * message, as it does an editor's: its first text part is what the Connected Agent wrote, and a
17
+ * second one, which only the model reads, says who sent it. Studios show it as the member's AI,
18
+ * never as the member.
19
+ */
20
+ export declare const CONNECTED_AGENT_MESSAGE_ENTRY = "camox.connected-agent-message";
13
21
  /** The kind of the transcript entry recording that an editor stopped a run, with them as data. */
14
22
  export declare const RUN_STOPPED_ENTRY = "camox.run-stopped";
15
23
  /**
@@ -103,6 +111,32 @@ export declare const threadSenderSchema: z.ZodObject<{
103
111
  export type ThreadSender = z.infer<typeof threadSenderSchema>;
104
112
  /** Whether `data` names a sender. */
105
113
  export declare const isSender: (data: unknown) => data is ThreadSender;
114
+ /**
115
+ * The app a Connected Agent runs in, by the name it gave: verified when it comes from a Client ID
116
+ * Metadata Document, self-asserted otherwise.
117
+ */
118
+ export declare const connectedAgentClientSchema: z.ZodObject<{
119
+ name: z.ZodString;
120
+ verified: z.ZodBoolean;
121
+ }, z.core.$strip>;
122
+ export type ConnectedAgentClient = z.infer<typeof connectedAgentClientSchema>;
123
+ /**
124
+ * What a Connected Agent's message entry records: the member it acts as, its client, and the
125
+ * operation id it was sent with.
126
+ */
127
+ export declare const connectedAgentMessageDataSchema: z.ZodObject<{
128
+ member: z.ZodObject<{
129
+ id: z.ZodString;
130
+ name: z.ZodString;
131
+ image: z.ZodNullable<z.ZodString>;
132
+ }, z.core.$strip>;
133
+ client: z.ZodObject<{
134
+ name: z.ZodString;
135
+ verified: z.ZodBoolean;
136
+ }, z.core.$strip>;
137
+ operationId: z.ZodOptional<z.ZodString>;
138
+ }, z.core.$strip>;
139
+ export type ConnectedAgentMessageData = z.infer<typeof connectedAgentMessageDataSchema>;
106
140
  /** What a push's entry records: who pushed, their commits' subjects, oldest first, and the build. */
107
141
  export declare const pushDataSchema: z.ZodObject<{
108
142
  pusher: z.ZodObject<{
@@ -236,6 +270,17 @@ export type ThreadMessage = {
236
270
  sender: ThreadSender;
237
271
  text: string;
238
272
  } |
273
+ /**
274
+ * A member's Connected Agent's message: the member's own AI, in its client, writing as itself.
275
+ * Never shown as the member's own words.
276
+ */
277
+ {
278
+ id: string;
279
+ from: "connectedAgent";
280
+ member: ThreadSender;
281
+ client: ConnectedAgentClient;
282
+ text: string;
283
+ } |
239
284
  /** Camox's own message, starting a turn it began itself: why it did. */
240
285
  {
241
286
  id: string;
@@ -337,6 +382,11 @@ type ThreadStep = {
337
382
  text: string;
338
383
  /** The draft the message went to, as the agent on Live handed the request off. */
339
384
  handedOffTo?: string;
385
+ } | {
386
+ type: "connectedAgent";
387
+ member: ThreadSender;
388
+ client: ConnectedAgentClient;
389
+ text: string;
340
390
  } |
341
391
  /** Camox starting a turn of its own, saying why. */
342
392
  {
package/dist/threads.js CHANGED
@@ -8,6 +8,14 @@ import { z } from "zod";
8
8
  * studio as they sent it (`editorTextOf`).
9
9
  */
10
10
  const EDITOR_MESSAGE_ENTRY = "camox.editor-message";
11
+ /**
12
+ * The kind of the transcript entry recording a Connected Agent's message (ADR 0030), with its
13
+ * member and client as data (`connectedAgentMessageDataSchema`). The model reads it as a user
14
+ * message, as it does an editor's: its first text part is what the Connected Agent wrote, and a
15
+ * second one, which only the model reads, says who sent it. Studios show it as the member's AI,
16
+ * never as the member.
17
+ */
18
+ const CONNECTED_AGENT_MESSAGE_ENTRY = "camox.connected-agent-message";
11
19
  /** The kind of the transcript entry recording that an editor stopped a run, with them as data. */
12
20
  const RUN_STOPPED_ENTRY = "camox.run-stopped";
13
21
  /**
@@ -97,6 +105,23 @@ const threadSenderSchema = z.object({
97
105
  });
98
106
  /** Whether `data` names a sender. */
99
107
  const isSender = (data) => threadSenderSchema.safeParse(data).success;
108
+ /**
109
+ * The app a Connected Agent runs in, by the name it gave: verified when it comes from a Client ID
110
+ * Metadata Document, self-asserted otherwise.
111
+ */
112
+ const connectedAgentClientSchema = z.object({
113
+ name: z.string(),
114
+ verified: z.boolean()
115
+ });
116
+ /**
117
+ * What a Connected Agent's message entry records: the member it acts as, its client, and the
118
+ * operation id it was sent with.
119
+ */
120
+ const connectedAgentMessageDataSchema = z.object({
121
+ member: threadSenderSchema,
122
+ client: connectedAgentClientSchema,
123
+ operationId: z.string().optional()
124
+ });
100
125
  /** What a push's entry records: who pushed, their commits' subjects, oldest first, and the build. */
101
126
  const pushDataSchema = z.object({
102
127
  pusher: threadSenderSchema,
@@ -291,6 +316,19 @@ function threadStepOf(entry) {
291
316
  ...handedOffTo && { handedOffTo }
292
317
  };
293
318
  }
319
+ if (entry.kind === "camox.connected-agent-message") {
320
+ const data = connectedAgentMessageDataSchema.safeParse(entry.data).data;
321
+ return data && {
322
+ id,
323
+ type: "connectedAgent",
324
+ member: senderOf(data.member),
325
+ client: {
326
+ name: data.client.name,
327
+ verified: data.client.verified
328
+ },
329
+ text: editorTextOf(message.content)
330
+ };
331
+ }
294
332
  if (entry.kind === "camox.brief") return {
295
333
  id,
296
334
  type: "camox",
@@ -374,6 +412,17 @@ function threadViewOf({ steps, running, toolCalls = [], callingTools = false, ch
374
412
  waiting = step.id;
375
413
  break;
376
414
  }
415
+ case "connectedAgent":
416
+ if (unfinished) fail();
417
+ messages.push({
418
+ id: step.id,
419
+ from: "connectedAgent",
420
+ member: step.member,
421
+ client: step.client,
422
+ text: step.text
423
+ });
424
+ waiting = step.id;
425
+ break;
377
426
  case "camox":
378
427
  if (unfinished) fail();
379
428
  messages.push({
@@ -566,4 +615,4 @@ function reduceThreadFrame(state, frame) {
566
615
  }
567
616
 
568
617
  //#endregion
569
- export { BRIEF_ENTRY, BUILD_STATUS_ENTRY, BUILD_TOOL, CHANGING_TOOLS, DRAFT_ENDED_ENTRY, EDITOR_MESSAGE_ENTRY, EMPTY_THREAD_STATE, EMPTY_THREAD_VIEW, PUSH_ENTRY, RECONCILE_ENTRY, RUN_STOPPED_ENTRY, START_DRAFT_TOOL, THREAD_ENDED_CLOSE_CODE, buildStatusDataSchema, buildStatusSchema, editorMessageDataSchema, editorSelectionSchema, editorTextOf, editorWhereSchema, isSender, pushDataSchema, pushOutcomeSchema, reconcileDataSchema, reduceThreadEvents, reduceThreadFrame, reduceThreadState, startedDraftCardSchema, startedDraftSchema, textOf, threadClientMessageSchema, threadSenderSchema, threadViewOf, touchKindSchema, touchSchema, touchedBatchSchema };
618
+ export { BRIEF_ENTRY, BUILD_STATUS_ENTRY, BUILD_TOOL, CHANGING_TOOLS, CONNECTED_AGENT_MESSAGE_ENTRY, DRAFT_ENDED_ENTRY, EDITOR_MESSAGE_ENTRY, EMPTY_THREAD_STATE, EMPTY_THREAD_VIEW, PUSH_ENTRY, RECONCILE_ENTRY, RUN_STOPPED_ENTRY, START_DRAFT_TOOL, THREAD_ENDED_CLOSE_CODE, buildStatusDataSchema, buildStatusSchema, connectedAgentClientSchema, connectedAgentMessageDataSchema, editorMessageDataSchema, editorSelectionSchema, editorTextOf, editorWhereSchema, isSender, pushDataSchema, pushOutcomeSchema, reconcileDataSchema, reduceThreadEvents, reduceThreadFrame, reduceThreadState, startedDraftCardSchema, startedDraftSchema, textOf, threadClientMessageSchema, threadSenderSchema, threadViewOf, touchKindSchema, touchSchema, touchedBatchSchema };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camox/api-contract",
3
- "version": "0.62.0",
3
+ "version": "0.63.0",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "src",
package/src/locales.ts CHANGED
@@ -15,6 +15,13 @@ export function localePrefix(locale: LocaleView): string {
15
15
  return locale.isDefault ? "" : `/${locale.tag.toLowerCase()}`;
16
16
  }
17
17
 
18
+ /** A locale-relative path under its locale's prefix, keeping its search and hash: `/` is `/de`. */
19
+ export function localizedPath(path: string, locale: LocaleView): string {
20
+ const prefix = localePrefix(locale);
21
+ if (!prefix) return path;
22
+ return path === "/" || /^\/[?#]/.test(path) ? `${prefix}${path.slice(1)}` : `${prefix}${path}`;
23
+ }
24
+
18
25
  /**
19
26
  * The locale a runtime path names, and the path after its prefix, without search or hash. A first
20
27
  * segment that isn't a non-default locale's prefix leaves the path the default locale's. A
package/src/threads.ts CHANGED
@@ -16,6 +16,15 @@ import type { DraftOutcome } from "./drafts.ts";
16
16
  */
17
17
  export const EDITOR_MESSAGE_ENTRY = "camox.editor-message";
18
18
 
19
+ /**
20
+ * The kind of the transcript entry recording a Connected Agent's message (ADR 0030), with its
21
+ * member and client as data (`connectedAgentMessageDataSchema`). The model reads it as a user
22
+ * message, as it does an editor's: its first text part is what the Connected Agent wrote, and a
23
+ * second one, which only the model reads, says who sent it. Studios show it as the member's AI,
24
+ * never as the member.
25
+ */
26
+ export const CONNECTED_AGENT_MESSAGE_ENTRY = "camox.connected-agent-message";
27
+
19
28
  /** The kind of the transcript entry recording that an editor stopped a run, with them as data. */
20
29
  export const RUN_STOPPED_ENTRY = "camox.run-stopped";
21
30
 
@@ -132,6 +141,24 @@ export type ThreadSender = z.infer<typeof threadSenderSchema>;
132
141
  export const isSender = (data: unknown): data is ThreadSender =>
133
142
  threadSenderSchema.safeParse(data).success;
134
143
 
144
+ /**
145
+ * The app a Connected Agent runs in, by the name it gave: verified when it comes from a Client ID
146
+ * Metadata Document, self-asserted otherwise.
147
+ */
148
+ export const connectedAgentClientSchema = z.object({ name: z.string(), verified: z.boolean() });
149
+ export type ConnectedAgentClient = z.infer<typeof connectedAgentClientSchema>;
150
+
151
+ /**
152
+ * What a Connected Agent's message entry records: the member it acts as, its client, and the
153
+ * operation id it was sent with.
154
+ */
155
+ export const connectedAgentMessageDataSchema = z.object({
156
+ member: threadSenderSchema,
157
+ client: connectedAgentClientSchema,
158
+ operationId: z.string().optional(),
159
+ });
160
+ export type ConnectedAgentMessageData = z.infer<typeof connectedAgentMessageDataSchema>;
161
+
135
162
  /** What a push's entry records: who pushed, their commits' subjects, oldest first, and the build. */
136
163
  export const pushDataSchema = z.object({
137
164
  pusher: threadSenderSchema,
@@ -205,6 +232,17 @@ export type TouchedBatch = z.infer<typeof touchedBatchSchema>;
205
232
  /** A message the studio shows in a thread. */
206
233
  export type ThreadMessage =
207
234
  | { id: string; from: "editor"; sender: ThreadSender; text: string }
235
+ /**
236
+ * A member's Connected Agent's message: the member's own AI, in its client, writing as itself.
237
+ * Never shown as the member's own words.
238
+ */
239
+ | {
240
+ id: string;
241
+ from: "connectedAgent";
242
+ member: ThreadSender;
243
+ client: ConnectedAgentClient;
244
+ text: string;
245
+ }
208
246
  /** Camox's own message, starting a turn it began itself: why it did. */
209
247
  | { id: string; from: "camox"; text: string }
210
248
  /** The agent's final message of a turn, in Markdown. */
@@ -290,6 +328,7 @@ type ThreadStep = { id: string } & (
290
328
  /** The draft the message went to, as the agent on Live handed the request off. */
291
329
  handedOffTo?: string;
292
330
  }
331
+ | { type: "connectedAgent"; member: ThreadSender; client: ConnectedAgentClient; text: string }
293
332
  /** Camox starting a turn of its own, saying why. */
294
333
  | { type: "camox"; text: string }
295
334
  | { type: "answer"; text: string }
@@ -461,6 +500,18 @@ function threadStepOf(entry: EntryRecord): ThreadStep | undefined {
461
500
  }
462
501
  );
463
502
  }
503
+ if (entry.kind === CONNECTED_AGENT_MESSAGE_ENTRY) {
504
+ const data = connectedAgentMessageDataSchema.safeParse(entry.data).data;
505
+ return (
506
+ data && {
507
+ id,
508
+ type: "connectedAgent",
509
+ member: senderOf(data.member)!,
510
+ client: { name: data.client.name, verified: data.client.verified },
511
+ text: editorTextOf(message.content),
512
+ }
513
+ );
514
+ }
464
515
  if (entry.kind === BRIEF_ENTRY) return { id, type: "camox", text: textOf(message.content) };
465
516
  if (entry.kind === RECONCILE_ENTRY) {
466
517
  const reconcile = reconcileDataSchema.safeParse(entry.data).data;
@@ -547,6 +598,18 @@ export function threadViewOf({
547
598
  waiting = step.id;
548
599
  break;
549
600
  }
601
+ case "connectedAgent":
602
+ // Like an editor's message: it starts a turn, or steers the one going.
603
+ if (unfinished) fail();
604
+ messages.push({
605
+ id: step.id,
606
+ from: "connectedAgent",
607
+ member: step.member,
608
+ client: step.client,
609
+ text: step.text,
610
+ });
611
+ waiting = step.id;
612
+ break;
550
613
  case "camox":
551
614
  if (unfinished) fail();
552
615
  messages.push({ id: step.id, from: "camox", text: step.text });