@uxnan/shared 0.0.17-alpha.20260926 → 0.0.18-alpha.20260926
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 +2 -2
- package/dist/src/agents/agent-adapter.d.ts +2 -1
- package/dist/src/agents/agent-capabilities.d.ts +2 -1
- package/dist/src/jsonrpc/methods.d.ts +0 -11
- package/dist/src/jsonrpc/notifications.d.ts +0 -21
- package/dist/src/jsonrpc/notifications.js +0 -5
- package/dist/src/jsonrpc/notifications.js.map +1 -1
- package/dist/src/local-control/local-control.d.ts +13 -1
- package/dist/src/local-control/local-control.js +14 -0
- package/dist/src/local-control/local-control.js.map +1 -1
- package/dist/src/models/session.d.ts +4 -2
- package/dist/src/models/thread.d.ts +6 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|

|
|
4
4
|

|
|
5
5
|

|
|
6
|
-

|
|
7
7
|
|
|
8
8
|
Shared JSON-RPC and E2EE contracts for the [Uxnan](../README.md) ecosystem — the
|
|
9
9
|
single source of truth every component agrees on. Consumed as a local workspace
|
|
@@ -13,7 +13,7 @@ equivalents (see
|
|
|
13
13
|
[`architecture/02b-contracts-and-requirements.md`](../architecture/02b-contracts-and-requirements.md)
|
|
14
14
|
§1 for the canonical contract list).
|
|
15
15
|
|
|
16
|
-
> **Status:** implemented and stable — **81 JSON-RPC methods** + **
|
|
16
|
+
> **Status:** implemented and stable — **81 JSON-RPC methods** + **21 streaming
|
|
17
17
|
> notifications**, kept lock-step at build time with the `METHOD_NAMES` array and
|
|
18
18
|
> the `StreamNotification` enum (a compile-time assertion in
|
|
19
19
|
> `src/jsonrpc/method-registry.ts` fails the build on any drift). Changes are
|
|
@@ -124,7 +124,8 @@ export interface IAgentAdapter {
|
|
|
124
124
|
* `activeTurnId` is the bridge turn currently in flight on the thread, so the
|
|
125
125
|
* adapter can address the right run (and refuse if it has already moved on).
|
|
126
126
|
* `turnId` is the queued turn the text came from — it does NOT start a run of
|
|
127
|
-
* its own
|
|
127
|
+
* its own: the bridge makes it the turn that carries the rest of this run,
|
|
128
|
+
* and keeps naming the run by `activeTurnId` in every call to the adapter.
|
|
128
129
|
*
|
|
129
130
|
* Returns **true only when the agent actually took the message**. Return
|
|
130
131
|
* `false` (don't throw) for an ordinary "too late / not applicable" — the
|
|
@@ -56,7 +56,8 @@ export interface AgentCapabilities {
|
|
|
56
56
|
* making it wait for the next one — what a CLI does when you type while it
|
|
57
57
|
* works and it picks the message up at the next tool boundary. The bridge
|
|
58
58
|
* hands such a turn straight to the adapter (`IAgentAdapter.steerTurn`)
|
|
59
|
-
* rather than holding it
|
|
59
|
+
* rather than holding it; the turn that was answering ends there and the new
|
|
60
|
+
* one carries the rest of the agent's run (architecture/02a §5.8.13).
|
|
60
61
|
*
|
|
61
62
|
* Optional; absent/false means the agent has no input channel mid-turn (a
|
|
62
63
|
* one-shot CLI, or a protocol that serializes prompts per session), and its
|
|
@@ -169,17 +169,6 @@ export interface TurnSendResult {
|
|
|
169
169
|
queued?: boolean;
|
|
170
170
|
/** 1-based place in the queue when `queued` is true (1 = runs next). */
|
|
171
171
|
queuePosition?: number;
|
|
172
|
-
/**
|
|
173
|
-
* True when the agent took the message **into the turn already running**
|
|
174
|
-
* rather than making it wait (status `delivered`, see `TurnStatus`). It will
|
|
175
|
-
* never run as a turn of its own — the reply belongs to the turn it joined —
|
|
176
|
-
* so the client renders the user's message in place and stops offering to
|
|
177
|
-
* edit or cancel it. Mutually exclusive with {@link queued}.
|
|
178
|
-
*
|
|
179
|
-
* Only ever true when the agent advertises `AgentCapabilities.steering`; on
|
|
180
|
-
* every other agent a follow-up still comes back `queued`.
|
|
181
|
-
*/
|
|
182
|
-
delivered?: boolean;
|
|
183
172
|
}
|
|
184
173
|
export interface QueueStateResult {
|
|
185
174
|
/** Queued turn ids in drain order. */
|
|
@@ -27,11 +27,6 @@ export declare const StreamNotification: {
|
|
|
27
27
|
readonly TurnAborted: "stream/turn/aborted";
|
|
28
28
|
/** A queued turn was removed before it ever ran (status → `cancelled`). */
|
|
29
29
|
readonly TurnCancelled: "stream/turn/cancelled";
|
|
30
|
-
/**
|
|
31
|
-
* A queued turn was handed to the agent **inside the turn already running**
|
|
32
|
-
* instead of waiting for it (status → `delivered`).
|
|
33
|
-
*/
|
|
34
|
-
readonly TurnDelivered: "stream/turn/delivered";
|
|
35
30
|
/** The thread's message queue changed (queued, drained, cancelled, paused). */
|
|
36
31
|
readonly QueueUpdated: "stream/queue/updated";
|
|
37
32
|
/** The agent resolved an alias (e.g. `opus`) to a concrete model id for this turn. */
|
|
@@ -149,22 +144,6 @@ export interface TurnCancelledParams {
|
|
|
149
144
|
threadId: string;
|
|
150
145
|
turnId: string;
|
|
151
146
|
}
|
|
152
|
-
/**
|
|
153
|
-
* A queued turn reached the agent **without waiting**: it was folded into the
|
|
154
|
-
* turn that was already running (its status is now `delivered`), the way a CLI
|
|
155
|
-
* picks up what you typed while it worked. It will never run as a turn of its
|
|
156
|
-
* own — the answer is part of `intoTurnId`.
|
|
157
|
-
*
|
|
158
|
-
* The client keeps the user's message where it is and stops offering to edit or
|
|
159
|
-
* cancel it: the agent already has it.
|
|
160
|
-
*/
|
|
161
|
-
export interface TurnDeliveredParams {
|
|
162
|
-
threadId: string;
|
|
163
|
-
/** The queued turn that was handed over. */
|
|
164
|
-
turnId: string;
|
|
165
|
-
/** The running turn it was folded into; its reply covers both messages. */
|
|
166
|
-
intoTurnId: string;
|
|
167
|
-
}
|
|
168
147
|
/**
|
|
169
148
|
* The thread's message queue changed. Carries the WHOLE state rather than a
|
|
170
149
|
* delta, so it is idempotent: a client that missed one (backgrounded, mid-
|
|
@@ -10,11 +10,6 @@ export const StreamNotification = {
|
|
|
10
10
|
TurnAborted: 'stream/turn/aborted',
|
|
11
11
|
/** A queued turn was removed before it ever ran (status → `cancelled`). */
|
|
12
12
|
TurnCancelled: 'stream/turn/cancelled',
|
|
13
|
-
/**
|
|
14
|
-
* A queued turn was handed to the agent **inside the turn already running**
|
|
15
|
-
* instead of waiting for it (status → `delivered`).
|
|
16
|
-
*/
|
|
17
|
-
TurnDelivered: 'stream/turn/delivered',
|
|
18
13
|
/** The thread's message queue changed (queued, drained, cancelled, paused). */
|
|
19
14
|
QueueUpdated: 'stream/queue/updated',
|
|
20
15
|
/** The agent resolved an alias (e.g. `opus`) to a concrete model id for this turn. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../../src/jsonrpc/notifications.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,WAAW,EAAE,qBAAqB;IAClC,YAAY,EAAE,sBAAsB;IACpC,kFAAkF;IAClF,aAAa,EAAE,uBAAuB;IACtC,mFAAmF;IACnF,YAAY,EAAE,sBAAsB;IACpC,aAAa,EAAE,uBAAuB;IACtC,SAAS,EAAE,mBAAmB;IAC9B,WAAW,EAAE,qBAAqB;IAClC,2EAA2E;IAC3E,aAAa,EAAE,uBAAuB;IACtC
|
|
1
|
+
{"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../../src/jsonrpc/notifications.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,WAAW,EAAE,qBAAqB;IAClC,YAAY,EAAE,sBAAsB;IACpC,kFAAkF;IAClF,aAAa,EAAE,uBAAuB;IACtC,mFAAmF;IACnF,YAAY,EAAE,sBAAsB;IACpC,aAAa,EAAE,uBAAuB;IACtC,SAAS,EAAE,mBAAmB;IAC9B,WAAW,EAAE,qBAAqB;IAClC,2EAA2E;IAC3E,aAAa,EAAE,uBAAuB;IACtC,+EAA+E;IAC/E,YAAY,EAAE,sBAAsB;IACpC,sFAAsF;IACtF,aAAa,EAAE,uBAAuB;IACtC;;;;OAIG;IACH,aAAa,EAAE,uBAAuB;IACtC,4BAA4B;IAC5B,aAAa,EAAE,uBAAuB;IACtC;;;;OAIG;IACH,WAAW,EAAE,qBAAqB;IAClC,oEAAoE;IACpE,gBAAgB,EAAE,0BAA0B;IAC5C,6EAA6E;IAC7E,gBAAgB,EAAE,0BAA0B;IAC5C,qDAAqD;IACrD,cAAc,EAAE,wBAAwB;IACxC,wEAAwE;IACxE,cAAc,EAAE,wBAAwB;IACxC,yEAAyE;IACzE,eAAe,EAAE,yBAAyB;IAC1C,0CAA0C;IAC1C,eAAe,EAAE,yBAAyB;IAC1C,uDAAuD;IACvD,cAAc,EAAE,wBAAwB;IACxC,qEAAqE;IACrE,aAAa,EAAE,uBAAuB;CAC9B,CAAC"}
|
|
@@ -86,7 +86,8 @@ export interface LocalControlMessageFrame {
|
|
|
86
86
|
export type LocalControlFrame = LocalControlHelloFrame | LocalControlMessageFrame;
|
|
87
87
|
/** Query parameters of the upgrade URL: `/control?client=<id>&resume=<seq>&instance=<id>`. */
|
|
88
88
|
export interface LocalControlConnectParams {
|
|
89
|
-
/** Stable name of the client (e.g. `desktop`); one live
|
|
89
|
+
/** Stable name of the client (e.g. `desktop-3f9a1c2b7d4e`, `cli`); one live
|
|
90
|
+
* connection per name. */
|
|
90
91
|
client: string;
|
|
91
92
|
/** Last notification `seq` the client applied (0 or absent on a fresh start). */
|
|
92
93
|
resume?: number;
|
|
@@ -95,6 +96,17 @@ export interface LocalControlConnectParams {
|
|
|
95
96
|
}
|
|
96
97
|
/** Whether `id` is an acceptable local client name (lowercase, short, no separators). */
|
|
97
98
|
export declare function isValidLocalClientId(id: string): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* The name Uxnan Desktop's client ids start with. Each desktop **profile** — the
|
|
101
|
+
* installed app, a development build, a disposable `UXNAN_DATA_DIR` — connects
|
|
102
|
+
* under its own `desktop-<profile>` id, because the channel keeps one live
|
|
103
|
+
* connection per name: two desktops sharing one would supersede each other in
|
|
104
|
+
* an endless reconnect loop and trade the same outbound log, presence and
|
|
105
|
+
* tools back and forth (architecture/02a §5.8.15).
|
|
106
|
+
*/
|
|
107
|
+
export declare const DESKTOP_LOCAL_CLIENT = "desktop";
|
|
108
|
+
/** Whether a local client id is Uxnan Desktop's (`desktop` or `desktop-<profile>`). */
|
|
109
|
+
export declare function isDesktopClientId(id: string): boolean;
|
|
98
110
|
/**
|
|
99
111
|
* The receiver id a local client is registered under in the bridge's session
|
|
100
112
|
* registry. Prefixed so it can never collide with a paired phone's device id.
|
|
@@ -36,6 +36,20 @@ const CLIENT_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,31}$/;
|
|
|
36
36
|
export function isValidLocalClientId(id) {
|
|
37
37
|
return CLIENT_ID_PATTERN.test(id);
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* The name Uxnan Desktop's client ids start with. Each desktop **profile** — the
|
|
41
|
+
* installed app, a development build, a disposable `UXNAN_DATA_DIR` — connects
|
|
42
|
+
* under its own `desktop-<profile>` id, because the channel keeps one live
|
|
43
|
+
* connection per name: two desktops sharing one would supersede each other in
|
|
44
|
+
* an endless reconnect loop and trade the same outbound log, presence and
|
|
45
|
+
* tools back and forth (architecture/02a §5.8.15).
|
|
46
|
+
*/
|
|
47
|
+
export const DESKTOP_LOCAL_CLIENT = 'desktop';
|
|
48
|
+
/** Whether a local client id is Uxnan Desktop's (`desktop` or `desktop-<profile>`). */
|
|
49
|
+
export function isDesktopClientId(id) {
|
|
50
|
+
return (isValidLocalClientId(id) &&
|
|
51
|
+
(id === DESKTOP_LOCAL_CLIENT || id.startsWith(`${DESKTOP_LOCAL_CLIENT}-`)));
|
|
52
|
+
}
|
|
39
53
|
/**
|
|
40
54
|
* The receiver id a local client is registered under in the bridge's session
|
|
41
55
|
* registry. Prefixed so it can never collide with a paired phone's device id.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-control.js","sourceRoot":"","sources":["../../../src/local-control/local-control.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,2DAA2D;AAC3D,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,oBAAoB,CAAC;AAEvD,0CAA0C;AAC1C,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAC;AAE7C;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"local-control.js","sourceRoot":"","sources":["../../../src/local-control/local-control.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,2DAA2D;AAC3D,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,oBAAoB,CAAC;AAEvD,0CAA0C;AAC1C,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAC;AAE7C;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAsE9D,MAAM,iBAAiB,GAAG,2BAA2B,CAAC;AAEtD,yFAAyF;AACzF,MAAM,UAAU,oBAAoB,CAAC,EAAU;IAC7C,OAAO,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACpC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAS,CAAC;AAE9C,uFAAuF;AACvF,MAAM,UAAU,iBAAiB,CAAC,EAAU;IAC1C,OAAO,CACL,oBAAoB,CAAC,EAAE,CAAC;QACxB,CAAC,EAAE,KAAK,oBAAoB,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,oBAAoB,GAAG,CAAC,CAAC,CAC3E,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,SAAS,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAuBD;;sCAEsC;AACtC,MAAM,CAAC,MAAM,kBAAkB,GAAG,aAAa,CAAC;AAEhD;;kBAEkB;AAClB,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC;AACjC,CAAC;AAED;;yBAEyB;AACzB,MAAM,CAAC,MAAM,uBAAuB,GAAG,eAAe,CAAC;AAEvD,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,OAAO,0DAA0D,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC9E,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAO,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -133,8 +133,10 @@ export interface BridgeFeatures {
|
|
|
133
133
|
messageQueue?: boolean;
|
|
134
134
|
/**
|
|
135
135
|
* The bridge can hand a queued turn to the agent **inside the turn already
|
|
136
|
-
* running**, for agents whose CLI has an input channel mid-turn —
|
|
137
|
-
*
|
|
136
|
+
* running**, for agents whose CLI has an input channel mid-turn — the running
|
|
137
|
+
* turn completes and the handed-over one starts at once, carrying the rest of
|
|
138
|
+
* the agent's run (`stream/turn/completed` then `stream/turn/started`, as a
|
|
139
|
+
* queue that drained early). Absent/false → the
|
|
138
140
|
* client must expect every follow-up to wait for the current turn to end, and
|
|
139
141
|
* must not promise otherwise in its UI.
|
|
140
142
|
*
|
|
@@ -17,14 +17,13 @@ export type MessageRole = 'user' | 'assistant' | 'system' | 'tool';
|
|
|
17
17
|
* thread (never deleted) so the user's message stays visible with a "cancelled"
|
|
18
18
|
* mark instead of silently vanishing; distinct from `aborted` precisely so a
|
|
19
19
|
* client can tell "never ran" from "interrupted".
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* with no assistant reply hanging off it.
|
|
20
|
+
*
|
|
21
|
+
* A queued turn the agent takes **into the turn already running** (see
|
|
22
|
+
* `AgentCapabilities.steering`) goes straight to `streaming`: the running turn
|
|
23
|
+
* completes there and this one carries the rest of the agent's run, so what the
|
|
24
|
+
* agent says after taking the message is shown under it.
|
|
26
25
|
*/
|
|
27
|
-
export type TurnStatus = 'queued' | 'pending' | 'streaming' | 'completed' | 'error' | 'aborted' | 'cancelled'
|
|
26
|
+
export type TurnStatus = 'queued' | 'pending' | 'streaming' | 'completed' | 'error' | 'aborted' | 'cancelled';
|
|
28
27
|
export type ThreadStatus = 'active' | 'idle' | 'archived';
|
|
29
28
|
/**
|
|
30
29
|
* Why a thread's message queue is held instead of draining:
|
|
@@ -81,12 +80,6 @@ export interface Turn {
|
|
|
81
80
|
messages: Message[];
|
|
82
81
|
createdAt: number;
|
|
83
82
|
completedAt?: number;
|
|
84
|
-
/**
|
|
85
|
-
* For a `delivered` turn: the id of the turn its message was folded into.
|
|
86
|
-
* The reply lives there, so a client renders this turn's user message in
|
|
87
|
-
* place and expects no assistant message of its own. Absent otherwise.
|
|
88
|
-
*/
|
|
89
|
-
deliveredIntoTurnId?: string;
|
|
90
83
|
}
|
|
91
84
|
/**
|
|
92
85
|
* Per-thread access (approval) mode: how much the agent may do before it must
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uxnan/shared",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18-alpha.20260926",
|
|
4
4
|
"description": "Shared JSON-RPC and E2EE contracts for the Uxnan ecosystem (bridge, relay, mobile).",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"author": "Luis Donaldo Gamas Vazquez",
|