@vinaverse/client 0.1.0-alpha.10 → 0.1.0-alpha.12
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 +22 -4
- package/dist/agent/index.cjs +43 -9
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +3 -3
- package/dist/agent/index.d.ts +3 -3
- package/dist/agent/index.js +1 -1
- package/dist/backend/index.cjs +37 -10
- package/dist/backend/index.cjs.map +1 -1
- package/dist/backend/index.d.cts +13 -3
- package/dist/backend/index.d.ts +13 -3
- package/dist/backend/index.js +38 -11
- package/dist/backend/index.js.map +1 -1
- package/dist/{chunk-O3NLAZGZ.js → chunk-5THD6XC7.js} +45 -11
- package/dist/chunk-5THD6XC7.js.map +1 -0
- package/dist/chunk-D56MNG3E.js +9 -0
- package/dist/{chunk-YNUHXJD6.js.map → chunk-D56MNG3E.js.map} +1 -1
- package/dist/contract-Be2oVHNr.d.cts +6 -0
- package/dist/contract-Be2oVHNr.d.ts +6 -0
- package/dist/conversation/index.cjs +2 -2
- package/dist/conversation/index.cjs.map +1 -1
- package/dist/conversation/index.d.cts +5 -5
- package/dist/conversation/index.d.ts +5 -5
- package/dist/conversation/index.js +1 -1
- package/dist/history/index.cjs +282 -0
- package/dist/history/index.cjs.map +1 -0
- package/dist/history/index.d.cts +91 -0
- package/dist/history/index.d.ts +91 -0
- package/dist/history/index.js +261 -0
- package/dist/history/index.js.map +1 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/{runtime-Z1RI10lU.d.ts → runtime-BR2lS_Vg.d.cts} +26 -3
- package/dist/{runtime-CISPp9nJ.d.cts → runtime-CZyVCueC.d.ts} +26 -3
- package/dist/{session-CPz4pcPu.d.cts → session-D0ijOQX3.d.cts} +98 -5
- package/dist/{session-CPz4pcPu.d.ts → session-D0ijOQX3.d.ts} +98 -5
- package/dist/{store-DZka9T2-.d.ts → store-CGRSxVcL.d.ts} +1 -1
- package/dist/{store-BxiicOKG.d.cts → store-CxoHwd64.d.cts} +1 -1
- package/dist/testing/index.cjs +158 -14
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +42 -5
- package/dist/testing/index.d.ts +42 -5
- package/dist/testing/index.js +159 -15
- package/dist/testing/index.js.map +1 -1
- package/package.json +24 -1
- package/dist/chunk-O3NLAZGZ.js.map +0 -1
- package/dist/chunk-YNUHXJD6.js +0 -9
- package/dist/contract-DmQs8amJ.d.cts +0 -6
- package/dist/contract-DmQs8amJ.d.ts +0 -6
package/README.md
CHANGED
|
@@ -139,7 +139,8 @@ app comes back to the foreground).
|
|
|
139
139
|
**Your backend, in two lines** (`@vinaverse/client/backend`): `backendFromFetch({ routes, headers })` is an
|
|
140
140
|
`AgentBackend` over your own routes, sending the person's credentials from `headers`, never in a body.
|
|
141
141
|
`backendRoutes(base)` gives the routes the .NET SDK's `MapVinaverseAgentSessions` serves by default (`session`,
|
|
142
|
-
`refresh`, `status`, `feedback`, `end`, `context`, `delete
|
|
142
|
+
`refresh`, `status`, `feedback`, `end`, `context`, `delete`, and history's `list` and `read`, answered
|
|
143
|
+
`{ version: 1, page }` as the gateway wrote the page); give your own where they differ. Both sides speak
|
|
143
144
|
`vinaverse.agent-backend/1` (vinaverse-contracts `docs/agent-backend.md`, tested here against its fixture): successes
|
|
144
145
|
wrapped with the version (`{ version: 1, session }`, `{ version: 1, client_secret: { value, expires_at } }`,
|
|
145
146
|
`{ version: 1, status }`, or 204), and one failure body for every route. Every session creation (a first open, a
|
|
@@ -182,7 +183,9 @@ against the session it was given in; a reply restored from the device or a resum
|
|
|
182
183
|
`{ screen: 'other' }`, no entity); revisions only grow across a conversation's sessions (`placeRevision` on the
|
|
183
184
|
session request), a `context_conflict` (409, with `current_revision`) sends the newest place once more above it, only while the session
|
|
184
185
|
and the person are the same, then says `moved`,
|
|
185
|
-
and a telling lands only on the session it was told to.
|
|
186
|
+
and a telling lands only on the session it was told to. One update is in flight per conversation: a place told meanwhile
|
|
187
|
+
(`show` and `tell` in one move, rapid moves) waits, only the newest, and goes next; a refusal that is no conflict is said
|
|
188
|
+
through `onWarning` (`context_refused`) in development builds. `onEvent` also says `message_sent`, `reply_completed` and
|
|
186
189
|
`card_shown` (never the words), its `key` is a salted SHA-256 hash of the conversation's key (`hashKey`), never the person's id: stable per install
|
|
187
190
|
(the salt is kept at `<persistenceKey>:salt` in your storage, a new one after `erase()`), and
|
|
188
191
|
`session_opened` says where the chat was opened from (`entryPoint`: `launcher`, `ask`, `deep_link`, or your own).
|
|
@@ -192,8 +195,23 @@ For a mock mode and tests, `@vinaverse/client/testing` has a scripted agent:
|
|
|
192
195
|
`createMockAgent({ script, reply, refuse, welcome })` gives an `AgentBackend` and a WebSocket factory that speaks the
|
|
193
196
|
protocol (`conversation.transport.webSocket`). `script` is the replies in order, one per turn, each with its text, its
|
|
194
197
|
cards or a failure; `reply` answers after it. `mockCards` gives the cards your tools would: `professional`,
|
|
195
|
-
`workspace`, `timeSlots`, `proposal` (pending, confirmed in your app) and `links`.
|
|
196
|
-
|
|
198
|
+
`workspace`, `timeSlots`, `proposal` (pending, confirmed in your app) and `links`. `history` scripts past
|
|
199
|
+
conversations (`{ id, title, state, items: [{ role, text, refusal? }, { card, proposal_outcome? }] }`): listed, read
|
|
200
|
+
back, continued with their messages, deleted (then `not_found`); a conversation begun in the mock is listed too once
|
|
201
|
+
something was said.
|
|
202
|
+
|
|
203
|
+
**History** (`@vinaverse/client/history`, an entry of its own): `createAgentHistory({ runtime, mode, scope, agent,
|
|
204
|
+
pageSize })` is the person's past conversations, newest activity first, a page at a time (`refresh`, `loadMore`, and
|
|
205
|
+
`retry` for the page that failed, the first or the next; `failure` says `off` when your backend serves no
|
|
206
|
+
`listConversations`; a cursor the gateway no longer takes, refused `unavailable` with its `invalid_request`, starts the
|
|
207
|
+
list over once, and any other refusal is said); `remove(key, id)` deletes through `runtime.deleteConversation` and drops
|
|
208
|
+
the row, one already gone too. `createAgentTranscript({ runtime, conversationId })` reads one back, the newest page
|
|
209
|
+
first and earlier pages prepended (`load`, `loadEarlier`, `retry`; a stale cursor reads back from the newest page
|
|
210
|
+
once), its items as the kits draw them (`historyItems`: messages
|
|
211
|
+
as sent, a cut-off reply and a guardrail's refusal kept, cards restored and inert, a proposal with the outcome it
|
|
212
|
+
had). `continueKey(conversation, subject)` is the key it continues under (its side and business as bound when it
|
|
213
|
+
started), for `runtime.continue` and `deleteConversation`. Nothing begun before a sign-out lands after it
|
|
214
|
+
(`runtime.epoch()`), nor a page from before a newer read.
|
|
197
215
|
|
|
198
216
|
The contract's types are exported too (`paths`, `components`, `operations`, `Schemas`): import them instead of copying
|
|
199
217
|
the spec. Design: [docs/architecture/agent-runtime.md](../../docs/architecture/agent-runtime.md).
|
package/dist/agent/index.cjs
CHANGED
|
@@ -2590,6 +2590,7 @@ var samePlace = (a, b) => a?.screen === b?.screen && (a?.entity?.type ?? null) =
|
|
|
2590
2590
|
function usable(session, insecure) {
|
|
2591
2591
|
return typeof session.id === "string" && session.id !== "" && (insecure.realtime === true || /^wss:\/\//i.test(session.realtime_url ?? "")) && (insecure.turns === true || /^https:\/\//i.test(session.turns_url ?? "")) && Boolean(session.client_secret);
|
|
2592
2592
|
}
|
|
2593
|
+
var devBuild = () => globalThis.__DEV__ === true;
|
|
2593
2594
|
function warnInsecure(insecure, warn) {
|
|
2594
2595
|
if (!(insecure.realtime || insecure.turns)) return;
|
|
2595
2596
|
if (globalThis.__DEV__ === true) return;
|
|
@@ -2908,6 +2909,8 @@ function createAgentRuntime(options) {
|
|
|
2908
2909
|
place: null,
|
|
2909
2910
|
told: null,
|
|
2910
2911
|
revision: 0,
|
|
2912
|
+
telling: false,
|
|
2913
|
+
queued: false,
|
|
2911
2914
|
entryPoint: null,
|
|
2912
2915
|
expiresAt: null,
|
|
2913
2916
|
shown: 0,
|
|
@@ -2942,26 +2945,55 @@ function createAgentRuntime(options) {
|
|
|
2942
2945
|
update(entry, { moved });
|
|
2943
2946
|
const updateContext = backend.updateContext?.bind(backend);
|
|
2944
2947
|
if (!moved || !updateContext || sessionId === null) return;
|
|
2948
|
+
if (entry.telling) {
|
|
2949
|
+
entry.queued = true;
|
|
2950
|
+
return;
|
|
2951
|
+
}
|
|
2952
|
+
entry.telling = true;
|
|
2945
2953
|
const asked = generation;
|
|
2946
2954
|
const current2 = () => asked === generation && live.get(entry.key) === entry && entry.state.sessionId === sessionId;
|
|
2955
|
+
const settle = () => {
|
|
2956
|
+
entry.telling = false;
|
|
2957
|
+
if (!entry.queued) return;
|
|
2958
|
+
entry.queued = false;
|
|
2959
|
+
if (asked === generation && live.get(entry.key) === entry)
|
|
2960
|
+
tell(entry, {});
|
|
2961
|
+
};
|
|
2947
2962
|
const send = (again) => {
|
|
2948
2963
|
const place = entry.place;
|
|
2949
2964
|
const revision = ++entry.revision;
|
|
2950
|
-
|
|
2965
|
+
let told;
|
|
2966
|
+
try {
|
|
2967
|
+
told = updateContext(sessionId, place ?? CLEARED, revision);
|
|
2968
|
+
} catch (error) {
|
|
2969
|
+
told = Promise.reject(error);
|
|
2970
|
+
}
|
|
2971
|
+
told.then(
|
|
2951
2972
|
() => {
|
|
2952
|
-
if (
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2973
|
+
if (current2() && entry.revision === revision) {
|
|
2974
|
+
entry.told = place;
|
|
2975
|
+
update(entry, { moved: !samePlace(entry.told, entry.place) });
|
|
2976
|
+
emit({ type: "context_updated", key: entry.key, sessionId });
|
|
2977
|
+
}
|
|
2978
|
+
settle();
|
|
2956
2979
|
},
|
|
2957
2980
|
(error) => {
|
|
2958
2981
|
const theirs = field(error, "currentRevision");
|
|
2959
2982
|
const conflict = field(error, "outcome") === "context_conflict" || field(error, "reason") === "conflict";
|
|
2960
|
-
if (
|
|
2983
|
+
if (conflict && !again && current2() && entry.revision === revision) {
|
|
2984
|
+
if (typeof theirs === "number" && theirs >= entry.revision)
|
|
2985
|
+
entry.revision = theirs;
|
|
2986
|
+
send(true);
|
|
2961
2987
|
return;
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2988
|
+
}
|
|
2989
|
+
if (!conflict && devBuild()) {
|
|
2990
|
+
const status2 = field(error, "status");
|
|
2991
|
+
warn(
|
|
2992
|
+
`@vinaverse/client/agent: updateContext was refused${typeof status2 === "number" ? ` (${status2})` : ""}: ${error instanceof Error ? error.message : String(error)}. The new place is offered as a question instead.`,
|
|
2993
|
+
{ code: "context_refused" }
|
|
2994
|
+
);
|
|
2995
|
+
}
|
|
2996
|
+
settle();
|
|
2965
2997
|
}
|
|
2966
2998
|
);
|
|
2967
2999
|
};
|
|
@@ -3126,6 +3158,8 @@ function createAgentRuntime(options) {
|
|
|
3126
3158
|
},
|
|
3127
3159
|
getStatus: () => status?.value ?? null,
|
|
3128
3160
|
getStatusState: () => statusState,
|
|
3161
|
+
backend,
|
|
3162
|
+
epoch: () => generation,
|
|
3129
3163
|
getName: () => sessionName ?? status?.value.displayName ?? null,
|
|
3130
3164
|
subscribe(listener) {
|
|
3131
3165
|
listeners.add(listener);
|