@company-semantics/contracts 86.0.0 → 87.0.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 +8 -8
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +50 -262
- package/src/chat/README.md +8 -20
- package/src/chat/__tests__/compaction-boundary.test.ts +1 -0
- package/src/chat/__tests__/continuity.test.ts +1 -0
- package/src/chat/__tests__/discussion-scope.test.ts +0 -7
- package/src/chat/__tests__/message-mentions.test.ts +1 -12
- package/src/chat/__tests__/multi-party.test.ts +15 -6
- package/src/chat/__tests__/page-context.test.ts +3 -3
- package/src/chat/enums.ts +24 -11
- package/src/chat/index.ts +4 -16
- package/src/chat/schemas.ts +9 -71
- package/src/chat/types.ts +25 -77
- package/src/generated/openapi-routes.ts +1 -4
- package/src/guards/config.ts +1 -1
- package/src/index.ts +4 -6
- package/src/mcp/__tests__/README.md +29 -0
- package/src/mcp/__tests__/resource-types-fixture.ts +50 -0
- package/src/mcp/__tests__/resources.test.ts +39 -0
- package/src/mcp/resources.ts +16 -1
- package/src/notifications/__tests__/__snapshots__/monospace-budget.test.ts.snap +4 -4
- package/src/notifications/__tests__/__snapshots__/render-snapshot.test.ts.snap +50 -49
- package/src/notifications/__tests__/fixtures.ts +7 -7
- package/src/notifications/__tests__/render-snapshot.test.ts +7 -7
- package/src/notifications/kinds/chat-shared.ts +11 -5
- package/src/notifications/payloads.ts +5 -5
- package/src/org/__tests__/view-scopes.test.ts +0 -2
- package/src/org/view-scopes.ts +0 -1
package/src/chat/README.md
CHANGED
|
@@ -29,7 +29,6 @@ Shared types for chat persistence, sharing, real-time events, and runtime profil
|
|
|
29
29
|
- Chat mention offsets are ZERO-BASED UTF-16 CODE UNITS into the exact `content` string with `endOffset` EXCLUSIVE, and no Unicode normalization happens anywhere on the path — the same convention as `CommentMention`, because a mention means the same thing on both surfaces. An astral character counts as TWO units
|
|
30
30
|
- Chat mention offsets are NULLABLE and null means "mentioned somewhere in this turn, highlight nothing", never an error. A user turn carries a real range; an assistant turn's mention is a typed part with no character range, and the nullability is what lets that land with no second schema
|
|
31
31
|
- Identity on a chat mention renders from the mention ROW, never from the content characters under the range. A stale range can only mis-highlight; it can never misattribute
|
|
32
|
-
- `SharedChatMessage` deliberately has NO mentions. The token-only share viewer is granted the CONTENT of a shared chat and nothing else; a mention row is identity, and identity is not in that grant
|
|
33
32
|
- `ChatMentionableResponse` carries `MentionableCandidate` items imported from `comments`, not a chat-flavored copy. A candidate is a principal, a display name and an avatar on both surfaces — and on both, deliberately no email and no access level, because a picker that returned the band each candidate holds would be a way to enumerate who can do what
|
|
34
33
|
- A chat message REQUIRES an `author`, and it is a `PrincipalRef` — so an assistant turn is the AGENT (`{ kind: "agent" }`), not a null and not a synthetic user id. `role` was sufficient while every chat had one human in it; with two participants `role: "user"` names a set, and a client with no author field can only render every human turn as the reader. That is silent misattribution, which is why this shipped in a MAJOR rather than as an optional field with a fallback (ADR-CONTRACTS-164)
|
|
35
34
|
- `author` is a ref, never a display name. Identity renders through a read-time lookup — the same rule as a mention row's `displayName` — so a rename re-renders the whole transcript with no backfill
|
|
@@ -37,7 +36,8 @@ Shared types for chat persistence, sharing, real-time events, and runtime profil
|
|
|
37
36
|
- `myRole` is per-READER, not a property of the chat: the same chat is `owner` to one person and `participant` to another over the same row shape. It is a hint for drawing; the server re-decides every owner-only action on its own
|
|
38
37
|
- The summary carries a participant COUNT, never the roster. A 50-row sidebar page must not carry 50 rosters, and a chat's membership is not disclosed by the chat merely appearing in a list. `ChatDetail.participants` is where the names are, and it is optional — a missing roster is simply not drawn, whereas a guessed role is drawn wrong
|
|
39
38
|
- A `ChatParticipant` is a USER, never a `PrincipalRef` — the deliberate asymmetry with a mention TARGET, which is a ref precisely so the agent can be named. The agent takes part in every chat by construction and has no participant row: it is mentionable, not a member, and cannot be added, removed or left
|
|
40
|
-
- `ChatParticipantRole`
|
|
39
|
+
- `ChatParticipantRole` is `owner` / `participant` (Collaborate) / `viewer` (Read only), and SHARING A CHAT IS ADDING A PARTICIPANT at one of the two grantable roles (`ChatGrantableRole`). Access is whole-chat or nothing — a viewer reads the same live conversation a participant does and writes nothing; there is no token, no snapshot and no public link (ADR-CONTRACTS-206)
|
|
40
|
+
- `ChatDetail.myRole` is REQUIRED, like the summary's: a chat opened from a link is on no loaded list page, and a guessed role draws a composer for a Read only viewer
|
|
41
41
|
- The chat schemas are THREE files with a one-way load order: `enums.ts` (the closed vocabularies plus the `proactiveChatFields` / `multiPartyChatFields` groups) imports nothing from the domain, `event-schemas.ts` imports only from it, and `schemas.ts` imports from both and RE-EXPORTS them so `index.ts`, `types.ts` and the tests keep one import site. An import from either of the first two back into `schemas.ts` is a load cycle: the re-export edge is evaluated before `schemas.ts`'s body, so the shared declarations are reached in the temporal dead zone and every consumer throws a `ReferenceError` at import time. `continuity.ts` sits outside that set on the same terms: `schemas.ts` imports it, it never imports `schemas.ts`, and `index.ts` re-exports it directly (its types are declared beside its schemas, as `runtime-profile.ts` does)
|
|
42
42
|
- `CHAT_PAGE_VIEWS` and `CHAT_PAGE_SCOPES` are a projection of the app's `Route` union (`company-semantics-app/src/platform/route-parser.ts`), not a parallel vocabulary. A view the parser can emit but the schema rejects fails the send outright rather than degrading
|
|
43
43
|
|
|
@@ -59,13 +59,14 @@ A chat can belong to a SUBJECT — the durable case a hand-off to chat is about
|
|
|
59
59
|
|
|
60
60
|
## Public API
|
|
61
61
|
|
|
62
|
+
- `AddChatParticipantRequest` _(type)_ — Request for POST /api/chats/:chatId/participants — sharing the chat with one org member at a grantable role.
|
|
62
63
|
- `BaseEvent` _(type)_ — Base envelope for all SSE events.
|
|
63
64
|
- `BaseEventSchema`
|
|
64
65
|
- `CHAT_CONTINUATION_REASONS` — Why a generation continues its predecessor.
|
|
65
66
|
- `CHAT_DISCUSSION_REQUEST_TYPES` — The kinds of durable input request a turn can be scoped to.
|
|
66
67
|
- `CHAT_PAGE_ENTITY_TYPES` — What kind of thing the reader has open, when they have one open.
|
|
67
68
|
- `CHAT_PAGE_SCOPES` — The route parser's four URL scopes: unscoped, `/me/*`, `/team/*`, `/@:org/*`.
|
|
68
|
-
- `CHAT_PAGE_VIEWS` — The app route parser's
|
|
69
|
+
- `CHAT_PAGE_VIEWS` — The app route parser's fifteen `type` values, projected onto the wire.
|
|
69
70
|
- `CHAT_RUNTIME_PROFILES` — Ordered list of available profiles for UI rendering.
|
|
70
71
|
- `CONVERSATION_SUBJECT_KINDS` — The kinds of subject a chat can continue.
|
|
71
72
|
- `ChatByInteractionResponse` _(type)_ — Response for GET /api/chats/by-interaction/:interactionId
|
|
@@ -86,6 +87,8 @@ A chat can belong to a SUBJECT — the durable case a hand-off to chat is about
|
|
|
86
87
|
- `ChatDiscussionScopeSchema` — WHAT THIS TURN IS ABOUT: one question of one input request, by stable id.
|
|
87
88
|
- `ChatDomainEvent` _(type)_ — All domain events that carry full state.
|
|
88
89
|
- `ChatDomainEventSchema`
|
|
90
|
+
- `ChatGrantableRole` _(type)_ — A role a share can grant: `participant` (Collaborate) or `viewer` (Read only).
|
|
91
|
+
- `ChatGrantableRoleSchema` — The roles a share can grant: Collaborate (`participant`) or Read only (`viewer`).
|
|
89
92
|
- `ChatInvalidationEvent` _(type)_ — All invalidation events that signal staleness.
|
|
90
93
|
- `ChatInvalidationEventSchema`
|
|
91
94
|
- `ChatListFilters` _(type)_ — Filters for listing chats.
|
|
@@ -102,15 +105,13 @@ A chat can belong to a SUBJECT — the durable case a hand-off to chat is about
|
|
|
102
105
|
- `ChatPageContext` _(type)_ — Where the reader is, as identifiers — route, view, scope and an optional `{ type, id }` entity.
|
|
103
106
|
- `ChatPageContextSchema` — Where the reader is, as identifiers.
|
|
104
107
|
- `ChatParticipant` _(type)_ — One ACTIVE participant of a chat — a user id, a role, a read-time display name and when they joined.
|
|
105
|
-
- `ChatParticipantRole` _(type)_ — What one person is to a chat: `owner` or `
|
|
108
|
+
- `ChatParticipantRole` _(type)_ — What one person is to a chat: `owner`, `participant` (Collaborate) or `viewer` (Read only).
|
|
106
109
|
- `ChatParticipantRoleSchema` — What one person is to a chat.
|
|
107
110
|
- `ChatParticipantSchema` — One active participant of a chat.
|
|
108
111
|
- `ChatParticipantsResponse` _(type)_ — Response for GET /api/chats/:chatId/participants.
|
|
109
112
|
- `ChatParticipantsResponseSchema` — Response for GET /api/chats/:chatId/participants.
|
|
110
113
|
- `ChatRuntimeProfile` _(type)_ — Chat runtime profile — user-selectable orchestration strategy.
|
|
111
114
|
- `ChatRuntimeProfileInfo` _(type)_ — Runtime profile metadata for UI rendering.
|
|
112
|
-
- `ChatShareInfo` _(type)_ — Chat share record with snapshot metadata.
|
|
113
|
-
- `ChatShareInfoSchema` — A chat share, as returned by the share APIs.
|
|
114
115
|
- `ChatSseEvent` _(type)_ — SSE event types for chat updates.
|
|
115
116
|
- `ChatSseEventSchema`
|
|
116
117
|
- `ChatSuccessResponse` _(type)_ — Generic mutation success confirmation.
|
|
@@ -121,15 +122,10 @@ A chat can belong to a SUBJECT — the durable case a hand-off to chat is about
|
|
|
121
122
|
- `ChatSummarySchema`
|
|
122
123
|
- `ChatUpdatedEvent` _(type)_ — Emitted when chat metadata changes (title, pin, etc.) Carries full current state - clients should replace…
|
|
123
124
|
- `ChatUpdatedEventSchema`
|
|
124
|
-
- `ChatVisibility` _(type)_ — Chat share visibility. - private: Token exists but access requires authentication as chat owner - public…
|
|
125
|
-
- `ChatVisibilitySchema`
|
|
126
125
|
- `ConversationSubjectKind` _(type)_
|
|
127
126
|
- `ConversationSubjectKindSchema`
|
|
128
127
|
- `CreateChatResponse` _(type)_ — Response for POST /api/chats
|
|
129
128
|
- `CreateChatResponseSchema` — Response for POST /api/chats
|
|
130
|
-
- `CreateShareRequest` _(type)_ — Request to create a new share for a chat.
|
|
131
|
-
- `CreateShareResponse` _(type)_ — Response for POST /api/chats/:chatId/shares
|
|
132
|
-
- `CreateShareResponseSchema` — Response for POST /api/chats/:chatId/shares
|
|
133
129
|
- `DEFAULT_CHAT_RUNTIME_PROFILE` — Default profile when none is specified in the request.
|
|
134
130
|
- `GetChatResponse` _(type)_ — Response for GET /api/chats/:id
|
|
135
131
|
- `GetChatResponseSchema` — Response for GET /api/chats/:id
|
|
@@ -145,17 +141,11 @@ A chat can belong to a SUBJECT — the durable case a hand-off to chat is about
|
|
|
145
141
|
- `LaunchDispositionSchema`
|
|
146
142
|
- `LaunchTargetSuperseded` _(type)_
|
|
147
143
|
- `LaunchTargetSupersededSchema` — The 409 body the authoritative launch write returns when the posted chat is not — or can no longer become —…
|
|
148
|
-
- `ListSharesResponse` _(type)_ — Response for GET /api/chats/:chatId/shares
|
|
149
|
-
- `ListSharesResponseSchema` — Response for GET /api/chats/:chatId/shares
|
|
150
144
|
- `ProactiveChatResolution` _(type)_ — Resolving an occurrence id to the CURRENT reader's chat — one of the four bounded states `ready` (with…
|
|
151
145
|
- `ProactiveChatResolutionSchema` — Resolving an occurrence id to THIS reader's chat (INV-PROACTIVE-LINK).
|
|
152
146
|
- `RecognizedProactiveKind` _(type)_ — A wire `proactiveKind` after recognition: a kind this contracts version knows, or the raw string it did not —…
|
|
153
147
|
- `ResolveLaunchResponse` _(type)_
|
|
154
148
|
- `ResolveLaunchResponseSchema` — Response of the read-only launch resolution.
|
|
155
|
-
- `SharedChatMessage` _(type)_ — Individual message in a shared chat view.
|
|
156
|
-
- `SharedChatMessageSchema`
|
|
157
|
-
- `SharedChatView` _(type)_ — Shared chat view returned to viewers.
|
|
158
|
-
- `SharedChatViewSchema`
|
|
159
149
|
- `StartFreshChatResponse` _(type)_
|
|
160
150
|
- `StartFreshChatResponseSchema` — Response of the start-fresh write: the NEW active generation of the subject, linked back to the chat it…
|
|
161
151
|
- `TitleGenerationRequest` _(type)_ — Request to generate a title for a chat.
|
|
@@ -163,9 +153,7 @@ A chat can belong to a SUBJECT — the durable case a hand-off to chat is about
|
|
|
163
153
|
- `TitleGenerationResponseSchema`
|
|
164
154
|
- `TitleSource` _(type)_ — Title source - tracks how the title was set. - auto: Generated automatically by LLM - manual: Set by user…
|
|
165
155
|
- `TitleSourceSchema`
|
|
166
|
-
- `
|
|
167
|
-
- `UpdateShareResponse` _(type)_ — Response for PATCH /api/shares/:shareId
|
|
168
|
-
- `UpdateShareResponseSchema` — Response for PATCH /api/shares/:shareId
|
|
156
|
+
- `UpdateChatParticipantRequest` _(type)_ — Request for PATCH /api/chats/:chatId/participants/:userId — the owner moving someone between Read only and…
|
|
169
157
|
- `recognizeProactiveKind` — Recognize a wire `proactiveKind`.
|
|
170
158
|
|
|
171
159
|
<!-- END GENERATED: readme-public-api -->
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
CHAT_DISCUSSION_REQUEST_TYPES,
|
|
12
12
|
ChatDiscussionScopeSchema,
|
|
13
13
|
ChatMessageSchema,
|
|
14
|
-
SharedChatMessageSchema,
|
|
15
14
|
} from "../schemas";
|
|
16
15
|
|
|
17
16
|
const VALID = {
|
|
@@ -90,12 +89,6 @@ describe("where a scope may be SEEN", () => {
|
|
|
90
89
|
expect("discussionScope" in ChatMessageSchema.shape).toBe(true);
|
|
91
90
|
});
|
|
92
91
|
|
|
93
|
-
it("is ABSENT from the shared-chat message, which is a separate type", () => {
|
|
94
|
-
// A token-only share reader sees the turn without its anchor line, and the
|
|
95
|
-
// question is named nowhere. This asymmetry is the design, not an oversight.
|
|
96
|
-
expect("discussionScope" in SharedChatMessageSchema.shape).toBe(false);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
92
|
it("is optional, so a turn about nothing in particular simply omits it", () => {
|
|
100
93
|
const parsed = ChatMessageSchema.shape.discussionScope.safeParse(undefined);
|
|
101
94
|
expect(parsed.success).toBe(true);
|
|
@@ -18,9 +18,6 @@
|
|
|
18
18
|
* exclusive. An astral character counts as TWO. Asserted against a real slice
|
|
19
19
|
* rather than stated, because a client measuring code POINTS produces ranges
|
|
20
20
|
* that look right until an emoji precedes the mention.
|
|
21
|
-
* - `SharedChatMessageSchema` did NOT gain mentions. The token-only share viewer
|
|
22
|
-
* renders content, not identity chips, and a mention row is identity a
|
|
23
|
-
* tokenholder was never granted.
|
|
24
21
|
* - `ChatMentionableResponseSchema` carries `MentionableCandidateSchema` items —
|
|
25
22
|
* the comments shape imported, not a chat-flavored copy of it.
|
|
26
23
|
*/
|
|
@@ -31,7 +28,6 @@ import {
|
|
|
31
28
|
ChatMessageMentionSchema,
|
|
32
29
|
ChatMessageSchema,
|
|
33
30
|
GetChatResponseSchema,
|
|
34
|
-
SharedChatMessageSchema,
|
|
35
31
|
} from "../schemas.js";
|
|
36
32
|
|
|
37
33
|
// ---------------------------------------------------------------------------
|
|
@@ -93,6 +89,7 @@ describe("ChatMessageSchema mentions", () => {
|
|
|
93
89
|
id: "chat_1",
|
|
94
90
|
title: "A conversation",
|
|
95
91
|
interactionId: "int_1",
|
|
92
|
+
myRole: "owner",
|
|
96
93
|
createdAt: "2026-09-02T00:00:00.000Z",
|
|
97
94
|
updatedAt: "2026-09-02T01:00:00.000Z",
|
|
98
95
|
continuity: null,
|
|
@@ -102,14 +99,6 @@ describe("ChatMessageSchema mentions", () => {
|
|
|
102
99
|
|
|
103
100
|
expect(parsed.messages[0].mentions).toHaveLength(1);
|
|
104
101
|
});
|
|
105
|
-
|
|
106
|
-
it("the share viewer's message shape did not gain mentions", () => {
|
|
107
|
-
// A token holder is granted the CONTENT of a shared chat and nothing else.
|
|
108
|
-
// Mention rows are identity, and identity is not in the grant.
|
|
109
|
-
expect(Object.keys(SharedChatMessageSchema.shape)).not.toContain(
|
|
110
|
-
"mentions",
|
|
111
|
-
);
|
|
112
|
-
});
|
|
113
102
|
});
|
|
114
103
|
|
|
115
104
|
describe("ChatMessageMentionSchema", () => {
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
ChatDetailSchema,
|
|
32
32
|
ChatMessageSchema,
|
|
33
33
|
ChatParticipantRoleSchema,
|
|
34
|
+
ChatGrantableRoleSchema,
|
|
34
35
|
ChatParticipantSchema,
|
|
35
36
|
ChatParticipantsResponseSchema,
|
|
36
37
|
ChatSummaryExtendedSchema,
|
|
@@ -122,6 +123,7 @@ const BASE_DETAIL = {
|
|
|
122
123
|
id: "chat_1",
|
|
123
124
|
title: "Q3 planning",
|
|
124
125
|
interactionId: "int_1",
|
|
126
|
+
myRole: "owner",
|
|
125
127
|
createdAt: ISO,
|
|
126
128
|
updatedAt: ISO,
|
|
127
129
|
continuity: null,
|
|
@@ -176,14 +178,21 @@ describe("ChatMessageSchema author", () => {
|
|
|
176
178
|
});
|
|
177
179
|
|
|
178
180
|
describe("the participant role vocabulary", () => {
|
|
179
|
-
it("
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
it("is owner, participant (Collaborate) and viewer (Read only) — ADR-CONTRACTS-206", () => {
|
|
182
|
+
expect(ChatParticipantRoleSchema.options).toEqual([
|
|
183
|
+
"owner",
|
|
184
|
+
"participant",
|
|
185
|
+
"viewer",
|
|
186
|
+
]);
|
|
183
187
|
});
|
|
184
188
|
|
|
185
|
-
it("
|
|
186
|
-
|
|
189
|
+
it("grants only Collaborate or Read only — owner is never granted", () => {
|
|
190
|
+
expect(ChatGrantableRoleSchema.options).toEqual(["participant", "viewer"]);
|
|
191
|
+
expect(ChatGrantableRoleSchema.safeParse("owner").success).toBe(false);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("rejects a band that is not whole-chat access", () => {
|
|
195
|
+
for (const role of ["commenter", "editor", "admin"]) {
|
|
187
196
|
expect(ChatParticipantRoleSchema.safeParse(role).success, role).toBe(
|
|
188
197
|
false,
|
|
189
198
|
);
|
|
@@ -211,9 +211,9 @@ describe("ChatPageContext is the ceiling on both axes", () => {
|
|
|
211
211
|
expect(ChatPageContextSchema.safeParse(VALID).success).toBe(true);
|
|
212
212
|
expect(
|
|
213
213
|
ChatPageContextSchema.safeParse({
|
|
214
|
-
route: "/
|
|
215
|
-
view: "
|
|
216
|
-
scope: "
|
|
214
|
+
route: "/me/work",
|
|
215
|
+
view: "work",
|
|
216
|
+
scope: "me",
|
|
217
217
|
entity: { type: "chat", id: "abc" },
|
|
218
218
|
}).success,
|
|
219
219
|
).toBe(true);
|
package/src/chat/enums.ts
CHANGED
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
|
|
21
21
|
import { z } from "zod";
|
|
22
22
|
|
|
23
|
-
export const ChatVisibilitySchema = z.enum(["private", "public"]);
|
|
24
23
|
export const TitleSourceSchema = z.enum(["auto", "manual"]);
|
|
25
24
|
export const InvalidationReasonSchema = z.enum([
|
|
26
25
|
"external-mutation",
|
|
@@ -44,18 +43,32 @@ export const ChatOriginSchema = z.enum(["user", "proactive"]);
|
|
|
44
43
|
/**
|
|
45
44
|
* What one person is to a chat.
|
|
46
45
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
46
|
+
* Participation with ONE access distinction, whole-chat or nothing:
|
|
47
|
+
* - `participant` (Collaborate) sees the whole live conversation, takes turns
|
|
48
|
+
* under the turn lock and may share the chat onward;
|
|
49
|
+
* - `viewer` (Read only) sees the same whole live conversation and writes
|
|
50
|
+
* nothing — no turn, no share, no retitle;
|
|
51
|
+
* - `owner` is the one participant who additionally deletes, renames, pins and
|
|
52
|
+
* changes another person's access.
|
|
53
|
+
*
|
|
54
|
+
* Sharing a chat IS adding a participant row with one of the two grantable
|
|
55
|
+
* roles (ADR-CONTRACTS-206). There is still no per-participant scope — a chat
|
|
56
|
+
* you can read half of is not a thing this surface models.
|
|
54
57
|
*
|
|
55
58
|
* EXACTLY ONE OWNER, and it never changes hands: ownership transfer is out of
|
|
56
59
|
* scope, and the owner cannot leave their own chat.
|
|
57
60
|
*/
|
|
58
|
-
export const ChatParticipantRoleSchema = z.enum([
|
|
61
|
+
export const ChatParticipantRoleSchema = z.enum([
|
|
62
|
+
"owner",
|
|
63
|
+
"participant",
|
|
64
|
+
"viewer",
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The roles a share can grant: Collaborate (`participant`) or Read only
|
|
69
|
+
* (`viewer`). `owner` is never granted — it is the chat's creator, once.
|
|
70
|
+
*/
|
|
71
|
+
export const ChatGrantableRoleSchema = z.enum(["participant", "viewer"]);
|
|
59
72
|
|
|
60
73
|
/**
|
|
61
74
|
* The three proactive wire fields, stated ONCE and spread into every shape
|
|
@@ -134,8 +147,8 @@ export const multiPartyChatFields = {
|
|
|
134
147
|
* the same chat is `owner` to one person and `participant` to another, and
|
|
135
148
|
* the same row shape reaches both.
|
|
136
149
|
*
|
|
137
|
-
* The client gates the owner-only affordances (delete, rename, pin,
|
|
138
|
-
* this. It is a hint for drawing, not the enforcement — the server re-decides
|
|
150
|
+
* The client gates the owner-only affordances (delete, rename, pin, access
|
|
151
|
+
* changes) and the read-only composer on this. It is a hint for drawing, not the enforcement — the server re-decides
|
|
139
152
|
* every one of them on its own.
|
|
140
153
|
*/
|
|
141
154
|
myRole: ChatParticipantRoleSchema,
|
package/src/chat/index.ts
CHANGED
|
@@ -10,13 +10,7 @@
|
|
|
10
10
|
// =============================================================================
|
|
11
11
|
|
|
12
12
|
export type {
|
|
13
|
-
ChatVisibility,
|
|
14
13
|
ChatSummary,
|
|
15
|
-
ChatShareInfo,
|
|
16
|
-
SharedChatView,
|
|
17
|
-
SharedChatMessage,
|
|
18
|
-
CreateShareRequest,
|
|
19
|
-
UpdateShareRequest,
|
|
20
14
|
// Chat lifecycle types
|
|
21
15
|
TitleSource,
|
|
22
16
|
ChatListFilters,
|
|
@@ -46,9 +40,6 @@ export type {
|
|
|
46
40
|
ChatByInteractionResponse,
|
|
47
41
|
ChatListResponse,
|
|
48
42
|
CreateChatResponse,
|
|
49
|
-
CreateShareResponse,
|
|
50
|
-
ListSharesResponse,
|
|
51
|
-
UpdateShareResponse,
|
|
52
43
|
ChatMessage,
|
|
53
44
|
// Mentions on a chat turn (ADR-CONTRACTS-160): a PrincipalRef target, so the
|
|
54
45
|
// agent is a legal mention target on the chat surface too.
|
|
@@ -57,6 +48,9 @@ export type {
|
|
|
57
48
|
// Participants (ADR-CONTRACTS-164): a chat is a room with a membership, not
|
|
58
49
|
// an ACL entity. The agent is mentionable but never a member.
|
|
59
50
|
ChatParticipantRole,
|
|
51
|
+
ChatGrantableRole,
|
|
52
|
+
AddChatParticipantRequest,
|
|
53
|
+
UpdateChatParticipantRequest,
|
|
60
54
|
ChatParticipant,
|
|
61
55
|
ChatParticipantsResponse,
|
|
62
56
|
ChatDetail,
|
|
@@ -71,7 +65,6 @@ export type {
|
|
|
71
65
|
// =============================================================================
|
|
72
66
|
|
|
73
67
|
export {
|
|
74
|
-
ChatVisibilitySchema,
|
|
75
68
|
TitleSourceSchema,
|
|
76
69
|
InvalidationReasonSchema,
|
|
77
70
|
ChatChangedFieldSchema,
|
|
@@ -80,9 +73,6 @@ export {
|
|
|
80
73
|
ChatSummaryExtendedSchema,
|
|
81
74
|
ProactiveChatResolutionSchema,
|
|
82
75
|
TitleGenerationResponseSchema,
|
|
83
|
-
SharedChatMessageSchema,
|
|
84
|
-
ChatShareInfoSchema,
|
|
85
|
-
SharedChatViewSchema,
|
|
86
76
|
BaseEventSchema,
|
|
87
77
|
ChatCreatedEventSchema,
|
|
88
78
|
ChatUpdatedEventSchema,
|
|
@@ -97,15 +87,13 @@ export {
|
|
|
97
87
|
ChatByInteractionResponseSchema,
|
|
98
88
|
ChatListResponseSchema,
|
|
99
89
|
CreateChatResponseSchema,
|
|
100
|
-
CreateShareResponseSchema,
|
|
101
|
-
ListSharesResponseSchema,
|
|
102
|
-
UpdateShareResponseSchema,
|
|
103
90
|
ChatMessageSchema,
|
|
104
91
|
ChatMessageMentionSchema,
|
|
105
92
|
ChatMentionableResponseSchema,
|
|
106
93
|
// Participants: the role vocabulary, one participant row, and the list
|
|
107
94
|
// envelope for GET /api/chats/:chatId/participants.
|
|
108
95
|
ChatParticipantRoleSchema,
|
|
96
|
+
ChatGrantableRoleSchema,
|
|
109
97
|
ChatParticipantSchema,
|
|
110
98
|
ChatParticipantsResponseSchema,
|
|
111
99
|
ChatDetailSchema,
|
package/src/chat/schemas.ts
CHANGED
|
@@ -21,7 +21,6 @@ import { PrincipalRefSchema } from "../identity/agent";
|
|
|
21
21
|
import { ChatContinuitySchema } from "./continuity";
|
|
22
22
|
import {
|
|
23
23
|
ChatParticipantRoleSchema,
|
|
24
|
-
ChatVisibilitySchema,
|
|
25
24
|
multiPartyChatFields,
|
|
26
25
|
proactiveChatFields,
|
|
27
26
|
TitleSourceSchema,
|
|
@@ -30,12 +29,12 @@ import {
|
|
|
30
29
|
// The chat vocabulary and the SSE event contract, re-exported so this module
|
|
31
30
|
// stays the single import site for every chat schema.
|
|
32
31
|
export {
|
|
33
|
-
ChatVisibilitySchema,
|
|
34
32
|
TitleSourceSchema,
|
|
35
33
|
InvalidationReasonSchema,
|
|
36
34
|
ChatChangedFieldSchema,
|
|
37
35
|
ChatOriginSchema,
|
|
38
36
|
ChatParticipantRoleSchema,
|
|
37
|
+
ChatGrantableRoleSchema,
|
|
39
38
|
} from "./enums";
|
|
40
39
|
|
|
41
40
|
export {
|
|
@@ -111,53 +110,6 @@ export const TitleGenerationResponseSchema = z.object({
|
|
|
111
110
|
isAutoGenerated: z.boolean(),
|
|
112
111
|
});
|
|
113
112
|
|
|
114
|
-
// =============================================================================
|
|
115
|
-
// Share Types
|
|
116
|
-
// =============================================================================
|
|
117
|
-
|
|
118
|
-
export const SharedChatMessageSchema = z.object({
|
|
119
|
-
role: z.enum(["user", "assistant"]),
|
|
120
|
-
content: z.string(),
|
|
121
|
-
parts: z.array(z.unknown()).optional(),
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* A chat share, as returned by the share APIs.
|
|
126
|
-
*
|
|
127
|
-
* SHOW-ONCE (ADR-BE-460). `token` and `shareUrl` are present ONLY on the
|
|
128
|
-
* response that creates the share. Share tokens are stored as a digest, so the
|
|
129
|
-
* server cannot redisplay one afterwards — listing or updating a share returns
|
|
130
|
-
* the record without them, and re-obtaining a link means revoke-and-reshare.
|
|
131
|
-
*
|
|
132
|
-
* This is the industry norm for capability links, and it is what removes the
|
|
133
|
-
* last reason to keep a recoverable copy of the token: a share list that can
|
|
134
|
-
* still show you the URL is a share list that can leak every live link at once.
|
|
135
|
-
* Consumers must treat both fields as optional and drive their copy-link
|
|
136
|
-
* affordance off creation, not off a fetched share.
|
|
137
|
-
*/
|
|
138
|
-
export const ChatShareInfoSchema = z.object({
|
|
139
|
-
id: z.string(),
|
|
140
|
-
chatId: z.string(),
|
|
141
|
-
/** Create-time only — never returned by list or update (show-once). */
|
|
142
|
-
token: z.string().optional(),
|
|
143
|
-
visibility: ChatVisibilitySchema,
|
|
144
|
-
/** Create-time only — never returned by list or update (show-once). */
|
|
145
|
-
shareUrl: z.string().optional(),
|
|
146
|
-
messageCountAtShare: z.number().int(),
|
|
147
|
-
titleAtShare: z.string(),
|
|
148
|
-
createdAt: IsoDateTime,
|
|
149
|
-
createdByName: z.string(),
|
|
150
|
-
isRevoked: z.boolean(),
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
export const SharedChatViewSchema = z.object({
|
|
154
|
-
title: z.string(),
|
|
155
|
-
messages: z.array(SharedChatMessageSchema),
|
|
156
|
-
sharedAt: IsoDateTime,
|
|
157
|
-
sharedByName: z.string(),
|
|
158
|
-
visibility: ChatVisibilitySchema,
|
|
159
|
-
});
|
|
160
|
-
|
|
161
113
|
// =============================================================================
|
|
162
114
|
// Message Types
|
|
163
115
|
// =============================================================================
|
|
@@ -331,10 +283,6 @@ export const ChatMessageSchema = z.object({
|
|
|
331
283
|
* not know this field renders the transcript exactly as it did before — the
|
|
332
284
|
* same reasoning as `compactedThroughSequence`.
|
|
333
285
|
*
|
|
334
|
-
* ON THE AUTHENTICATED TRANSCRIPT ONLY. `SharedChatMessageSchema` is a
|
|
335
|
-
* separate type and does not carry it, so a scoped turn shown to a token-only
|
|
336
|
-
* share reader has no anchor line and names no question. That asymmetry is
|
|
337
|
-
* the point, not an oversight.
|
|
338
286
|
*/
|
|
339
287
|
discussionScope: ChatDiscussionScopeSchema.optional(),
|
|
340
288
|
});
|
|
@@ -398,22 +346,6 @@ export const CreateChatResponseSchema = z.object({
|
|
|
398
346
|
chat: ChatSummaryExtendedSchema,
|
|
399
347
|
});
|
|
400
348
|
|
|
401
|
-
/** Response for POST /api/chats/:chatId/shares */
|
|
402
|
-
export const CreateShareResponseSchema = z.object({
|
|
403
|
-
share: ChatShareInfoSchema,
|
|
404
|
-
shareUrl: z.string(),
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
/** Response for GET /api/chats/:chatId/shares */
|
|
408
|
-
export const ListSharesResponseSchema = z.object({
|
|
409
|
-
shares: z.array(ChatShareInfoSchema),
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
/** Response for PATCH /api/shares/:shareId */
|
|
413
|
-
export const UpdateShareResponseSchema = z.object({
|
|
414
|
-
share: ChatShareInfoSchema,
|
|
415
|
-
});
|
|
416
|
-
|
|
417
349
|
/**
|
|
418
350
|
* Chat detail object in GET /api/chats/:id response.
|
|
419
351
|
* Extends the base summary with interactionId (needed for append-on-edit flows).
|
|
@@ -469,6 +401,13 @@ export const ChatDetailSchema = z.object({
|
|
|
469
401
|
* an empty array is not a state the server produces.
|
|
470
402
|
*/
|
|
471
403
|
participants: z.array(ChatParticipantSchema).optional(),
|
|
404
|
+
/**
|
|
405
|
+
* What the READER is to this chat — the same per-reader fact the summary
|
|
406
|
+
* carries as `myRole`, on the detail too so a chat opened from a link (and
|
|
407
|
+
* so on no loaded list page) still knows whether to draw a composer.
|
|
408
|
+
* REQUIRED: guessing it draws a composer for a Read only viewer.
|
|
409
|
+
*/
|
|
410
|
+
myRole: ChatParticipantRoleSchema,
|
|
472
411
|
/**
|
|
473
412
|
* The chat's place in its subject's lineage (chat-continuity-wire-vocabulary).
|
|
474
413
|
* NULL for a chat that belongs to no subject. REQUIRED, not optional: a
|
|
@@ -509,7 +448,7 @@ export const ChatMentionableResponseSchema = z.object({
|
|
|
509
448
|
// =============================================================================
|
|
510
449
|
|
|
511
450
|
/**
|
|
512
|
-
* The app route parser's
|
|
451
|
+
* The app route parser's fifteen `type` values, projected onto the wire.
|
|
513
452
|
*
|
|
514
453
|
* A PROJECTION, not a parallel vocabulary: keep it in step with
|
|
515
454
|
* `company-semantics-app/src/platform/route-parser.ts`. A view the parser can
|
|
@@ -518,7 +457,6 @@ export const ChatMentionableResponseSchema = z.object({
|
|
|
518
457
|
* reads that parser's source and compares the two.
|
|
519
458
|
*/
|
|
520
459
|
export const CHAT_PAGE_VIEWS = [
|
|
521
|
-
"chat",
|
|
522
460
|
"company-md",
|
|
523
461
|
"execution-detail",
|
|
524
462
|
"internal-admin",
|