@sparkelf/dsh-group-chat 0.0.0-stage → 0.2.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/README.md CHANGED
@@ -1,3 +1,91 @@
1
- # Temporary Holding Version
1
+ ---
2
+ kind: package-readme
3
+ ---
2
4
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
5
+ # @sparkelf/dsh-group-chat
6
+
7
+ Human-agent group chat for DataOps-managed DSH workspaces.
8
+
9
+ A room is a message bus shared by its members. Every member's workspace keeps its own
10
+ copy of every message, and each member's agent is a **local subscriber** that acts
11
+ only on its own instructions:
12
+
13
+ | Situation | What happens |
14
+ | --- | --- |
15
+ | Any member posts anything | Broadcast to every member; each workspace appends it to the room's session, so each agent can read the whole conversation |
16
+ | A member mentions **themselves** | That member's own agent runs a turn |
17
+ | A member mentions someone else | Ordinary message — recorded and read, never executed |
18
+ | `@everyone`, or no mention | Ordinary message — no agent runs |
19
+
20
+ ## Why the mention rule is this narrow
21
+
22
+ One rule decides every case: **a message runs an agent only when its sender
23
+ mentioned themselves.** Everything else is recorded and read, never executed.
24
+
25
+ That is a deliberate trade, and it is what makes the design safe and simple:
26
+
27
+ - **Nobody can drive someone else's agent.** A mention never reaches another
28
+ member's container, so it can never spend their model budget or reach their files.
29
+ - **No fan-out.** `@everyone` is an ordinary message, so it does not start N agent
30
+ runs.
31
+ - **Visibility is not gated, only execution.** Every message still enters every
32
+ agent's context, so an agent answering later has read the whole conversation.
33
+
34
+ The trade is that a room has no shared intelligence — only each member's own agent
35
+ plus a shared transcript. In exchange, no cross-container coordination protocol,
36
+ consensus algorithm, or distributed transaction is needed.
37
+
38
+ ## Architecture
39
+
40
+ ```
41
+ DataOps backend ← identity, global order, storage, routing
42
+ ↑ POST (ack) ↓ pull (cursor)
43
+ workspace container ← one DSH per member
44
+ agent + session log
45
+ ```
46
+
47
+ - **Uplink** is an awaited POST. The backend assigns the globally ordered id and
48
+ returns the finalized event; the event is appended locally **only after** that
49
+ acknowledgement, so a rejected message never enters the append-only log.
50
+ - **Downlink** is a cursor pull. The backend is the only cross-container
51
+ intersection point, so it is also the only authority on order; a cursor is the
52
+ entire synchronization state and survives a restart.
53
+ - **Idempotency** is `source.rpcId` — the identity DSH already mints for reconciling
54
+ optimistic and durable messages — enforced by a unique index, so a retried or
55
+ double-clicked send produces one message.
56
+ - **Only the turn's final `assistant/message` is published.** Intermediate steps,
57
+ file reads, and tool output never leave the member's own workspace.
58
+
59
+ ## Configuration
60
+
61
+ The plugin reads the workspace identity DataOps already injects into the container.
62
+ It mints no credential of its own:
63
+
64
+ | Variable | Purpose |
65
+ | --- | --- |
66
+ | `DATAOPS_AI_WORKSPACE_INTERNAL_TOKEN` | Credential the backend verifies |
67
+ | `DATAOPS_AI_WORKSPACE_USER_ID` | The account this workspace belongs to |
68
+ | `DATAOPS_AI_WORKSPACE_BACKEND_BASE_URL` | Backend origin |
69
+ | `DATAOPS_AI_WORKSPACE_MOUNT_PATH` | Workspace root, used as the room session's `cwd` |
70
+
71
+ **On any DSH where those are absent — a developer's own installation, for
72
+ instance — the plugin registers nothing at all:** no route, no listener, no timer.
73
+ Ordinary sessions are byte-identical with and without it installed. This is asserted
74
+ by a test whose context throws on every property read.
75
+
76
+ ## Rooms and sessions
77
+
78
+ One room maps to one DSH session, named `group-room-<roomId>`. The binding lives in
79
+ the session id because `SessionHeader` carries no free-form metadata field. An
80
+ ordinary session never matches that prefix, which is the second half of how this
81
+ plugin stays out of the way.
82
+
83
+ ## Known limits
84
+
85
+ - **Display names are not authentication.** The backend verifies *who* a caller is
86
+ (a workspace-scoped HMAC binds the credential to one account); it does not verify
87
+ what they type as their name.
88
+ - **A member's nickname is a snapshot.** It is copied at write time so a later
89
+ rename cannot rewrite history.
90
+ - **Offline members catch up by cursor.** A workspace that stays unreachable keeps a
91
+ gap in its local copy; the plugin does not fabricate a completeness marker for it.
@@ -0,0 +1,3 @@
1
+ - insert:
2
+ - id: group-chat
3
+ name: '@sparkelf/dsh-group-chat'