@cerebro-labs/agentnava-sdk 0.75.1 → 0.80.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 +56 -2
- package/account.d.ts +1 -1
- package/account.js +1 -1
- package/account.js.map +1 -1
- package/agent.d.ts +49 -5
- package/agent.js +45 -2
- package/agent.js.map +1 -1
- package/end-user.d.ts +83 -32
- package/end-user.js +101 -38
- package/end-user.js.map +1 -1
- package/index.d.ts +1 -1
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/react.d.ts +3 -1
- package/react.js +18 -2
- package/react.js.map +1 -1
- package/secret.d.ts +1 -1
- package/secret.js +1 -1
- package/secret.js.map +1 -1
- package/types.d.ts +80 -1
- package/types.js.map +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.js.map +1 -1
- package/workspace.d.ts +4 -56
- package/workspace.js +7 -46
- package/workspace.js.map +1 -1
package/end-user.d.ts
CHANGED
|
@@ -3,8 +3,15 @@ import { Secret } from './secret.ts';
|
|
|
3
3
|
import { Conversation } from './conversation.ts';
|
|
4
4
|
import type { Http } from './http.ts';
|
|
5
5
|
import type { AppId } from './apps.generated.ts';
|
|
6
|
+
import type { MemoryData } from './types.ts';
|
|
6
7
|
/**
|
|
7
|
-
* One of YOUR end users, as this platform sees them.
|
|
8
|
+
* One of YOUR end users, of ONE agent, as this platform sees them.
|
|
9
|
+
*
|
|
10
|
+
* EACH AGENT IS ITS OWN APP, WITH ITS OWN END USERS. The same id on two agents is
|
|
11
|
+
* two different people, with separate accounts, secrets and conversations. A
|
|
12
|
+
* person using two of your agents signs in to each. There is no workspace-wide
|
|
13
|
+
* end user, and no way to erase one, because the same id on another agent may be
|
|
14
|
+
* someone else.
|
|
8
15
|
*
|
|
9
16
|
* WHY THE NAME IS `EndUser` AND NOT `User`. There are two populations of people
|
|
10
17
|
* in this product, and calling both of them "user" was a bug waiting to be
|
|
@@ -13,10 +20,11 @@ import type { AppId } from './apps.generated.ts';
|
|
|
13
20
|
* | | workspace member | END USER |
|
|
14
21
|
* |---|---|---|
|
|
15
22
|
* | who | your colleague, on a seat | the person your application serves |
|
|
23
|
+
* | belongs to | the workspace | one agent |
|
|
16
24
|
* | signs in to this platform | yes | NEVER |
|
|
17
25
|
* | who issues the id | we do | YOUR database |
|
|
18
26
|
* | do we authenticate it | yes | no, deliberately |
|
|
19
|
-
* | in this SDK | `ws.members()` | `
|
|
27
|
+
* | in this SDK | `ws.members()` | `agent.endUser(id)` |
|
|
20
28
|
*
|
|
21
29
|
* They were both spelled `userId`, so `ws.members()` handed you an id that
|
|
22
30
|
* `agent.start()` would accept without complaint and label a conversation with
|
|
@@ -43,21 +51,22 @@ import type { AppId } from './apps.generated.ts';
|
|
|
43
51
|
* // once, in the agent's setup: each person uses their own Gmail
|
|
44
52
|
* await agent.connections.add(Connection.endUserAccount(App.GMAIL));
|
|
45
53
|
*
|
|
46
|
-
* const ananya =
|
|
54
|
+
* const ananya = agent.endUser(row.userId); // no request
|
|
47
55
|
* const { url } = await ananya.accounts.connect({ app: App.GMAIL });
|
|
48
|
-
* showToUser(url); // she signs in ONCE
|
|
56
|
+
* showToUser(url); // she signs in ONCE, for this agent
|
|
49
57
|
*
|
|
50
58
|
* const conversation = await agent.start({ endUserId: ananya.id });
|
|
51
59
|
* await conversation.ask('what did I miss this morning?');
|
|
52
60
|
*
|
|
53
|
-
* await ananya.conversations(); // everything of hers,
|
|
61
|
+
* await ananya.conversations(); // everything of hers, with this agent
|
|
62
|
+
* await ananya.erase(); // she left: all of it, on this agent
|
|
54
63
|
* ```
|
|
55
64
|
*
|
|
56
65
|
* WHAT NAMING AN END USER DOES, exactly. `start({ endUserId })` labels the
|
|
57
66
|
* conversation so it can be listed back to them, and it decides whose account
|
|
58
|
-
* a connection to the end user's account uses: this person's,
|
|
59
|
-
* and nobody else's. The grant is the agent's setup, which you can read;
|
|
60
|
-
* falls back to the workspace's account or to anybody else's.
|
|
67
|
+
* a connection to the end user's account uses: this person's, on this agent, for
|
|
68
|
+
* that app, and nobody else's. The grant is the agent's setup, which you can read;
|
|
69
|
+
* it never falls back to the workspace's account, or to anybody else's.
|
|
61
70
|
*
|
|
62
71
|
* THE ID IS YOURS. A row id from your database, opaque to us, and we never
|
|
63
72
|
* authenticate it. We are not an identity provider and do not want to be. It
|
|
@@ -69,20 +78,23 @@ import type { AppId } from './apps.generated.ts';
|
|
|
69
78
|
export declare class EndUser {
|
|
70
79
|
#private;
|
|
71
80
|
readonly id: string;
|
|
72
|
-
|
|
81
|
+
/** The agent this person belongs to, as you addressed it. */
|
|
82
|
+
readonly agentId: string;
|
|
83
|
+
constructor(http: Http, agentId: string, id: string);
|
|
73
84
|
private get base();
|
|
74
85
|
/**
|
|
75
|
-
* This person's own accounts: the "end user's account" that a
|
|
76
|
-
* built with `Connection.endUserAccount(app)` uses.
|
|
86
|
+
* This person's own accounts on this agent: the "end user's account" that a
|
|
87
|
+
* connection built with `Connection.endUserAccount(app)` uses.
|
|
77
88
|
*
|
|
78
89
|
* Connected ONCE, on the app's own page. After that the account is theirs
|
|
79
|
-
* and stays theirs: every conversation of theirs
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* conversation.
|
|
90
|
+
* on this agent and stays theirs: every conversation of theirs with this agent
|
|
91
|
+
* uses it, and nobody is sent through a sign-in again per thread. Nothing is
|
|
92
|
+
* attached per conversation.
|
|
83
93
|
*
|
|
84
94
|
* An agent never reaches these any other way: not through the workspace's
|
|
85
|
-
* own account of the same app,
|
|
95
|
+
* own account of the same app, not in another person's conversation, and not
|
|
96
|
+
* on another agent. The same id on another agent is another person, who signs
|
|
97
|
+
* in there.
|
|
86
98
|
*/
|
|
87
99
|
readonly accounts: {
|
|
88
100
|
/** Begin connecting one of their accounts. Returns it, still `pending`,
|
|
@@ -97,14 +109,15 @@ export declare class EndUser {
|
|
|
97
109
|
account: Account;
|
|
98
110
|
url: string;
|
|
99
111
|
}>;
|
|
100
|
-
/** Theirs alone. The agent creators' accounts are not here:
|
|
112
|
+
/** Theirs on this agent alone. The agent creators' accounts are not here:
|
|
101
113
|
* `ws.accounts.list()` is the view that shows those. */
|
|
102
114
|
list: () => Promise<Account[]>;
|
|
103
115
|
/**
|
|
104
|
-
* Disconnect every account they connected, in one call
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
116
|
+
* Disconnect every account they connected on this agent, in one call, so it
|
|
117
|
+
* is not a loop the caller has to remember to write. Every conversation of
|
|
118
|
+
* theirs with this agent stops reaching those apps from the next turn, and
|
|
119
|
+
* nothing is kept. Returns how many were disconnected. To remove everything
|
|
120
|
+
* about them, use `erase()`.
|
|
108
121
|
*/
|
|
109
122
|
disconnectAll: () => Promise<{
|
|
110
123
|
disconnected: number;
|
|
@@ -129,7 +142,7 @@ export declare class EndUser {
|
|
|
129
142
|
* explicit line:
|
|
130
143
|
*
|
|
131
144
|
* ```ts
|
|
132
|
-
* const ananya =
|
|
145
|
+
* const ananya = agent.endUser(row.userId);
|
|
133
146
|
* const key = await ananya.secrets.create({ name: 'ZENDESK_TOKEN', value: token });
|
|
134
147
|
*
|
|
135
148
|
* const conversation = await agent.start({ endUserId: ananya.id });
|
|
@@ -139,8 +152,9 @@ export declare class EndUser {
|
|
|
139
152
|
* TWO THINGS THE PLATFORM ENFORCES, neither of which you can turn off:
|
|
140
153
|
* the agent must DECLARE that secret name at session scope, so attaching by
|
|
141
154
|
* id is not a way around the allowlist; and a secret belonging to one end
|
|
142
|
-
* user can only be attached to a conversation launched for that same person
|
|
143
|
-
* so one mistyped id cannot hand Ananya's key to somebody
|
|
155
|
+
* user can only be attached to a conversation launched for that same person
|
|
156
|
+
* with this same agent, so one mistyped id cannot hand Ananya's key to somebody
|
|
157
|
+
* else's turn.
|
|
144
158
|
* Both are checked again at every tool call, not only when you attach.
|
|
145
159
|
*
|
|
146
160
|
* THE CONVERSATION FOLLOWS THE SECRET. It keeps a pointer, never a copy, so
|
|
@@ -155,26 +169,63 @@ export declare class EndUser {
|
|
|
155
169
|
name: string;
|
|
156
170
|
value: string;
|
|
157
171
|
description?: string;
|
|
158
|
-
agentId?: string;
|
|
159
172
|
/** The only hosts a tool may send it to, checked at every call of a
|
|
160
173
|
* conversation it is attached to. Left out, it goes only to the host
|
|
161
174
|
* the agent's tool writes out in full. */
|
|
162
175
|
allowedHosts?: string[];
|
|
163
176
|
}) => Promise<Secret>;
|
|
164
|
-
/** This person's secrets, values excluded. The workspace's own
|
|
165
|
-
* here: `ws.secrets.list()` answers that. */
|
|
177
|
+
/** This person's secrets on this agent, values excluded. The workspace's own
|
|
178
|
+
* are not in here: `ws.secrets.list()` answers that. */
|
|
166
179
|
list: () => Promise<Secret[]>;
|
|
167
180
|
};
|
|
168
181
|
/**
|
|
169
|
-
*
|
|
182
|
+
* What this agent remembers about them. Nothing here runs during a chat: this
|
|
183
|
+
* is for your own screens and tools. Your whole team may read and edit it, and
|
|
184
|
+
* an API key may.
|
|
170
185
|
*
|
|
171
|
-
*
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
186
|
+
* Nothing in it is secret from them: the agent can repeat any line if they ask.
|
|
187
|
+
*/
|
|
188
|
+
readonly memory: {
|
|
189
|
+
/** Their memory. Empty text if there is none yet. */
|
|
190
|
+
get: () => Promise<MemoryData>;
|
|
191
|
+
/**
|
|
192
|
+
* Replace it, one fact per line, at most 30 lines. Refused if it holds a card,
|
|
193
|
+
* key or id number, or is too long. Chats from before this save can no longer
|
|
194
|
+
* change it.
|
|
195
|
+
*/
|
|
196
|
+
set: (text: string) => Promise<MemoryData>;
|
|
197
|
+
/** Delete it. No copy is kept, and their earlier chats cannot bring it back. A later chat can start a new one. */
|
|
198
|
+
delete: () => Promise<void>;
|
|
199
|
+
/** They asked to stop: delete it and keep nothing more about them. `false` undoes this, only if they ask. */
|
|
200
|
+
stop: (stopped?: boolean) => Promise<MemoryData>;
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* Everything this person has said to this agent, newest first. Pass `before`
|
|
204
|
+
* from the previous page to keep going, rather than being capped at 200.
|
|
175
205
|
*/
|
|
176
206
|
conversations(options?: {
|
|
177
207
|
limit?: number;
|
|
178
208
|
before?: string;
|
|
179
209
|
}): Promise<Conversation[]>;
|
|
210
|
+
/**
|
|
211
|
+
* Delete everything about them on this agent, in one call: their accounts
|
|
212
|
+
* (signed out at the app first), their secrets, their conversations, the wakeups
|
|
213
|
+
* those conversations set, and what the agent remembers about them. What off-boarding and an erasure request call.
|
|
214
|
+
*
|
|
215
|
+
* This agent only. The same id on another agent may be someone else, so there
|
|
216
|
+
* is no workspace-wide erase: if one person uses two of your agents, erase them
|
|
217
|
+
* from each. A schedule you configured on the agent to name them stays, because
|
|
218
|
+
* it is your setup. A project's conversations belong to the project and are
|
|
219
|
+
* deleted by id.
|
|
220
|
+
*
|
|
221
|
+
* Safe to call again. An account that cannot be signed out fails the call with
|
|
222
|
+
* the rest still in place, so a credential is never orphaned. A turn still running
|
|
223
|
+
* when this lands can write after it, and a second call clears what it left.
|
|
224
|
+
* Returns how many of each went.
|
|
225
|
+
*/
|
|
226
|
+
erase(): Promise<{
|
|
227
|
+
accounts: number;
|
|
228
|
+
secrets: number;
|
|
229
|
+
conversations: number;
|
|
230
|
+
}>;
|
|
180
231
|
}
|
package/end-user.js
CHANGED
|
@@ -3,7 +3,13 @@ import { Account, accountIn } from "./account.js";
|
|
|
3
3
|
import { Secret } from "./secret.js";
|
|
4
4
|
import { Conversation } from "./conversation.js";
|
|
5
5
|
/**
|
|
6
|
-
* One of YOUR end users, as this platform sees them.
|
|
6
|
+
* One of YOUR end users, of ONE agent, as this platform sees them.
|
|
7
|
+
*
|
|
8
|
+
* EACH AGENT IS ITS OWN APP, WITH ITS OWN END USERS. The same id on two agents is
|
|
9
|
+
* two different people, with separate accounts, secrets and conversations. A
|
|
10
|
+
* person using two of your agents signs in to each. There is no workspace-wide
|
|
11
|
+
* end user, and no way to erase one, because the same id on another agent may be
|
|
12
|
+
* someone else.
|
|
7
13
|
*
|
|
8
14
|
* WHY THE NAME IS `EndUser` AND NOT `User`. There are two populations of people
|
|
9
15
|
* in this product, and calling both of them "user" was a bug waiting to be
|
|
@@ -12,10 +18,11 @@ import { Conversation } from "./conversation.js";
|
|
|
12
18
|
* | | workspace member | END USER |
|
|
13
19
|
* |---|---|---|
|
|
14
20
|
* | who | your colleague, on a seat | the person your application serves |
|
|
21
|
+
* | belongs to | the workspace | one agent |
|
|
15
22
|
* | signs in to this platform | yes | NEVER |
|
|
16
23
|
* | who issues the id | we do | YOUR database |
|
|
17
24
|
* | do we authenticate it | yes | no, deliberately |
|
|
18
|
-
* | in this SDK | `ws.members()` | `
|
|
25
|
+
* | in this SDK | `ws.members()` | `agent.endUser(id)` |
|
|
19
26
|
*
|
|
20
27
|
* They were both spelled `userId`, so `ws.members()` handed you an id that
|
|
21
28
|
* `agent.start()` would accept without complaint and label a conversation with
|
|
@@ -42,21 +49,22 @@ import { Conversation } from "./conversation.js";
|
|
|
42
49
|
* // once, in the agent's setup: each person uses their own Gmail
|
|
43
50
|
* await agent.connections.add(Connection.endUserAccount(App.GMAIL));
|
|
44
51
|
*
|
|
45
|
-
* const ananya =
|
|
52
|
+
* const ananya = agent.endUser(row.userId); // no request
|
|
46
53
|
* const { url } = await ananya.accounts.connect({ app: App.GMAIL });
|
|
47
|
-
* showToUser(url); // she signs in ONCE
|
|
54
|
+
* showToUser(url); // she signs in ONCE, for this agent
|
|
48
55
|
*
|
|
49
56
|
* const conversation = await agent.start({ endUserId: ananya.id });
|
|
50
57
|
* await conversation.ask('what did I miss this morning?');
|
|
51
58
|
*
|
|
52
|
-
* await ananya.conversations(); // everything of hers,
|
|
59
|
+
* await ananya.conversations(); // everything of hers, with this agent
|
|
60
|
+
* await ananya.erase(); // she left: all of it, on this agent
|
|
53
61
|
* ```
|
|
54
62
|
*
|
|
55
63
|
* WHAT NAMING AN END USER DOES, exactly. `start({ endUserId })` labels the
|
|
56
64
|
* conversation so it can be listed back to them, and it decides whose account
|
|
57
|
-
* a connection to the end user's account uses: this person's,
|
|
58
|
-
* and nobody else's. The grant is the agent's setup, which you can read;
|
|
59
|
-
* falls back to the workspace's account or to anybody else's.
|
|
65
|
+
* a connection to the end user's account uses: this person's, on this agent, for
|
|
66
|
+
* that app, and nobody else's. The grant is the agent's setup, which you can read;
|
|
67
|
+
* it never falls back to the workspace's account, or to anybody else's.
|
|
60
68
|
*
|
|
61
69
|
* THE ID IS YOURS. A row id from your database, opaque to us, and we never
|
|
62
70
|
* authenticate it. We are not an identity provider and do not want to be. It
|
|
@@ -67,26 +75,30 @@ import { Conversation } from "./conversation.js";
|
|
|
67
75
|
*/
|
|
68
76
|
export class EndUser {
|
|
69
77
|
id;
|
|
78
|
+
/** The agent this person belongs to, as you addressed it. */
|
|
79
|
+
agentId;
|
|
70
80
|
#http;
|
|
71
|
-
constructor(http, id) {
|
|
81
|
+
constructor(http, agentId, id) {
|
|
72
82
|
this.#http = http;
|
|
83
|
+
this.agentId = agentId;
|
|
73
84
|
this.id = id;
|
|
74
85
|
}
|
|
75
86
|
get base() {
|
|
76
|
-
return `/v1/end-users/${encodeURIComponent(this.id)}
|
|
87
|
+
return `/v1/agents/${encodeURIComponent(this.agentId)}/end-users/${encodeURIComponent(this.id)}`;
|
|
77
88
|
}
|
|
78
89
|
/**
|
|
79
|
-
* This person's own accounts: the "end user's account" that a
|
|
80
|
-
* built with `Connection.endUserAccount(app)` uses.
|
|
90
|
+
* This person's own accounts on this agent: the "end user's account" that a
|
|
91
|
+
* connection built with `Connection.endUserAccount(app)` uses.
|
|
81
92
|
*
|
|
82
93
|
* Connected ONCE, on the app's own page. After that the account is theirs
|
|
83
|
-
* and stays theirs: every conversation of theirs
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* conversation.
|
|
94
|
+
* on this agent and stays theirs: every conversation of theirs with this agent
|
|
95
|
+
* uses it, and nobody is sent through a sign-in again per thread. Nothing is
|
|
96
|
+
* attached per conversation.
|
|
87
97
|
*
|
|
88
98
|
* An agent never reaches these any other way: not through the workspace's
|
|
89
|
-
* own account of the same app,
|
|
99
|
+
* own account of the same app, not in another person's conversation, and not
|
|
100
|
+
* on another agent. The same id on another agent is another person, who signs
|
|
101
|
+
* in there.
|
|
90
102
|
*/
|
|
91
103
|
accounts = {
|
|
92
104
|
/** Begin connecting one of their accounts. Returns it, still `pending`,
|
|
@@ -96,27 +108,28 @@ export class EndUser {
|
|
|
96
108
|
* hands you the same kind of link for whatever a conversation is still
|
|
97
109
|
* missing. */
|
|
98
110
|
connect: async (input) => {
|
|
99
|
-
// FIELDS PICKED: the person
|
|
100
|
-
const res = await this.#http.post(`${this.base}/connect`, {
|
|
111
|
+
// FIELDS PICKED: the agent and the person come from the path, never from the body.
|
|
112
|
+
const res = await this.#http.post(`${this.base}/accounts/connect`, {
|
|
101
113
|
app: input.app,
|
|
102
114
|
});
|
|
103
|
-
const account = accountIn(res, `${this.base}/connect`);
|
|
115
|
+
const account = accountIn(res, `${this.base}/accounts/connect`);
|
|
104
116
|
return { account: new Account(this.#http, account.id, account), url: res.url };
|
|
105
117
|
},
|
|
106
|
-
/** Theirs alone. The agent creators' accounts are not here:
|
|
118
|
+
/** Theirs on this agent alone. The agent creators' accounts are not here:
|
|
107
119
|
* `ws.accounts.list()` is the view that shows those. */
|
|
108
120
|
list: async () => {
|
|
109
|
-
const res = await this.#http.get(this.base);
|
|
121
|
+
const res = await this.#http.get(`${this.base}/accounts`);
|
|
110
122
|
return (res.accounts ?? []).map((a) => new Account(this.#http, a.id, a));
|
|
111
123
|
},
|
|
112
124
|
/**
|
|
113
|
-
* Disconnect every account they connected, in one call
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
125
|
+
* Disconnect every account they connected on this agent, in one call, so it
|
|
126
|
+
* is not a loop the caller has to remember to write. Every conversation of
|
|
127
|
+
* theirs with this agent stops reaching those apps from the next turn, and
|
|
128
|
+
* nothing is kept. Returns how many were disconnected. To remove everything
|
|
129
|
+
* about them, use `erase()`.
|
|
117
130
|
*/
|
|
118
131
|
disconnectAll: async () => {
|
|
119
|
-
const res = await this.#http.delete(this.base);
|
|
132
|
+
const res = await this.#http.delete(`${this.base}/accounts`);
|
|
120
133
|
return { disconnected: res?.disconnected ?? 0 };
|
|
121
134
|
},
|
|
122
135
|
};
|
|
@@ -139,7 +152,7 @@ export class EndUser {
|
|
|
139
152
|
* explicit line:
|
|
140
153
|
*
|
|
141
154
|
* ```ts
|
|
142
|
-
* const ananya =
|
|
155
|
+
* const ananya = agent.endUser(row.userId);
|
|
143
156
|
* const key = await ananya.secrets.create({ name: 'ZENDESK_TOKEN', value: token });
|
|
144
157
|
*
|
|
145
158
|
* const conversation = await agent.start({ endUserId: ananya.id });
|
|
@@ -149,8 +162,9 @@ export class EndUser {
|
|
|
149
162
|
* TWO THINGS THE PLATFORM ENFORCES, neither of which you can turn off:
|
|
150
163
|
* the agent must DECLARE that secret name at session scope, so attaching by
|
|
151
164
|
* id is not a way around the allowlist; and a secret belonging to one end
|
|
152
|
-
* user can only be attached to a conversation launched for that same person
|
|
153
|
-
* so one mistyped id cannot hand Ananya's key to somebody
|
|
165
|
+
* user can only be attached to a conversation launched for that same person
|
|
166
|
+
* with this same agent, so one mistyped id cannot hand Ananya's key to somebody
|
|
167
|
+
* else's turn.
|
|
154
168
|
* Both are checked again at every tool call, not only when you attach.
|
|
155
169
|
*
|
|
156
170
|
* THE CONVERSATION FOLLOWS THE SECRET. It keeps a pointer, never a copy, so
|
|
@@ -170,37 +184,86 @@ export class EndUser {
|
|
|
170
184
|
name: input.name,
|
|
171
185
|
value: input.value,
|
|
172
186
|
endUserId: this.id,
|
|
187
|
+
agentId: this.agentId,
|
|
173
188
|
...(input.description !== undefined && { description: input.description }),
|
|
174
|
-
...(input.agentId !== undefined && { agentId: input.agentId }),
|
|
175
189
|
...(input.allowedHosts !== undefined && { allowedHosts: input.allowedHosts }),
|
|
176
190
|
});
|
|
177
191
|
const meta = res.secret ?? res;
|
|
178
192
|
return new Secret(this.#http, meta.id, meta);
|
|
179
193
|
},
|
|
180
|
-
/** This person's secrets, values excluded. The workspace's own
|
|
181
|
-
* here: `ws.secrets.list()` answers that. */
|
|
194
|
+
/** This person's secrets on this agent, values excluded. The workspace's own
|
|
195
|
+
* are not in here: `ws.secrets.list()` answers that. */
|
|
182
196
|
list: async () => {
|
|
183
197
|
const res = await this.#http.get('/v1/secrets', {
|
|
184
198
|
end_user_id: this.id,
|
|
199
|
+
agentId: this.agentId,
|
|
185
200
|
});
|
|
186
201
|
return (res.secrets ?? []).map((m) => new Secret(this.#http, m.id, m));
|
|
187
202
|
},
|
|
188
203
|
};
|
|
189
204
|
/**
|
|
190
|
-
*
|
|
205
|
+
* What this agent remembers about them. Nothing here runs during a chat: this
|
|
206
|
+
* is for your own screens and tools. Your whole team may read and edit it, and
|
|
207
|
+
* an API key may.
|
|
191
208
|
*
|
|
192
|
-
*
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
209
|
+
* Nothing in it is secret from them: the agent can repeat any line if they ask.
|
|
210
|
+
*/
|
|
211
|
+
memory = {
|
|
212
|
+
/** Their memory. Empty text if there is none yet. */
|
|
213
|
+
get: () => this.#http.get(`${this.base}/memory`),
|
|
214
|
+
/**
|
|
215
|
+
* Replace it, one fact per line, at most 30 lines. Refused if it holds a card,
|
|
216
|
+
* key or id number, or is too long. Chats from before this save can no longer
|
|
217
|
+
* change it.
|
|
218
|
+
*/
|
|
219
|
+
set: (text) => this.#http.put(`${this.base}/memory`, { text }),
|
|
220
|
+
/** Delete it. No copy is kept, and their earlier chats cannot bring it back. A later chat can start a new one. */
|
|
221
|
+
delete: async () => {
|
|
222
|
+
await this.#http.delete(`${this.base}/memory`);
|
|
223
|
+
},
|
|
224
|
+
/** They asked to stop: delete it and keep nothing more about them. `false` undoes this, only if they ask. */
|
|
225
|
+
stop: (stopped = true) => this.#http.put(`${this.base}/memory/stop`, { stopped }),
|
|
226
|
+
};
|
|
227
|
+
/**
|
|
228
|
+
* Everything this person has said to this agent, newest first. Pass `before`
|
|
229
|
+
* from the previous page to keep going, rather than being capped at 200.
|
|
196
230
|
*/
|
|
197
231
|
async conversations(options = {}) {
|
|
198
232
|
const res = await this.#http.get('/v1/conversations', {
|
|
233
|
+
agentId: this.agentId,
|
|
199
234
|
end_user_id: this.id,
|
|
200
235
|
...(options.limit !== undefined && { limit: options.limit }),
|
|
201
236
|
...(options.before && { before: options.before }),
|
|
202
237
|
});
|
|
203
238
|
return (res.conversations ?? []).map((c) => new Conversation(this.#http, c.id, c));
|
|
204
239
|
}
|
|
240
|
+
/**
|
|
241
|
+
* Delete everything about them on this agent, in one call: their accounts
|
|
242
|
+
* (signed out at the app first), their secrets, their conversations, the wakeups
|
|
243
|
+
* those conversations set, and what the agent remembers about them. What off-boarding and an erasure request call.
|
|
244
|
+
*
|
|
245
|
+
* This agent only. The same id on another agent may be someone else, so there
|
|
246
|
+
* is no workspace-wide erase: if one person uses two of your agents, erase them
|
|
247
|
+
* from each. A schedule you configured on the agent to name them stays, because
|
|
248
|
+
* it is your setup. A project's conversations belong to the project and are
|
|
249
|
+
* deleted by id.
|
|
250
|
+
*
|
|
251
|
+
* Safe to call again. An account that cannot be signed out fails the call with
|
|
252
|
+
* the rest still in place, so a credential is never orphaned. A turn still running
|
|
253
|
+
* when this lands can write after it, and a second call clears what it left.
|
|
254
|
+
* Returns how many of each went.
|
|
255
|
+
*/
|
|
256
|
+
async erase() {
|
|
257
|
+
const total = { accounts: 0, secrets: 0, conversations: 0 };
|
|
258
|
+
let more = true;
|
|
259
|
+
while (more) {
|
|
260
|
+
const res = await this.#http.delete(this.base);
|
|
261
|
+
total.accounts += res?.accounts ?? 0;
|
|
262
|
+
total.secrets += res?.secrets ?? 0;
|
|
263
|
+
total.conversations += res?.conversations ?? 0;
|
|
264
|
+
more = res?.more === true;
|
|
265
|
+
}
|
|
266
|
+
return total;
|
|
267
|
+
}
|
|
205
268
|
}
|
|
206
269
|
//# sourceMappingURL=end-user.js.map
|
package/end-user.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"end-user.js","sourceRoot":"","sources":["../src/end-user.ts"],"names":[],"mappings":"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","sourcesContent":["// One of YOUR end users: a person your application serves, who never signs in here.\n\nimport { Account, accountIn } from './account.ts';\nimport { Secret } from './secret.ts';\nimport { Conversation } from './conversation.ts';\nimport type { Http } from './http.ts';\nimport type { AppId } from './apps.generated.ts';\nimport type { AccountData, AgentConversationData, SecretMeta } from './types.ts';\n\n/**\n * One of YOUR end users, as this platform sees them.\n *\n * WHY THE NAME IS `EndUser` AND NOT `User`. There are two populations of people\n * in this product, and calling both of them \"user\" was a bug waiting to be\n * written:\n *\n * | | workspace member | END USER |\n * |---|---|---|\n * | who | your colleague, on a seat | the person your application serves |\n * | signs in to this platform | yes | NEVER |\n * | who issues the id | we do | YOUR database |\n * | do we authenticate it | yes | no, deliberately |\n * | in this SDK | `ws.members()` | `ws.endUser(id)` |\n *\n * They were both spelled `userId`, so `ws.members()` handed you an id that\n * `agent.start()` would accept without complaint and label a conversation with\n * a teammate's internal platform id. It could never have errored, because an\n * end-user id is never checked against anything. The two names now make that\n * call impossible to write by accident.\n *\n * NOT `Customer`, which was tried and reverted. Two reasons. \"Customer\" already\n * means the party that BUYS this platform, in our own strategy documents and in\n * `subscriptions.stripe_customer_id`, so the word points the other way. And it\n * is wrong for the common case: an enterprise deploying an internal workflow\n * agent serves its own EMPLOYEES, who are not anybody's customers.\n *\n * WHY THIS OBJECT EXISTS. You are building an application for many people.\n * Ananya has her own Gmail, her own conversations and her own history, and so\n * do the other ten thousand. Every call you make is on behalf of one of them.\n *\n * Without this, the person is an argument: `endUserId` threaded through\n * `accounts.connect`, `secrets.create`, `conversations` and `start`, and\n * forgotten in exactly one of them one day. With it, you say who once and the\n * rest follows:\n *\n * ```ts\n * // once, in the agent's setup: each person uses their own Gmail\n * await agent.connections.add(Connection.endUserAccount(App.GMAIL));\n *\n * const ananya = ws.endUser(row.userId); // no request\n * const { url } = await ananya.accounts.connect({ app: App.GMAIL });\n * showToUser(url); // she signs in ONCE\n *\n * const conversation = await agent.start({ endUserId: ananya.id });\n * await conversation.ask('what did I miss this morning?');\n *\n * await ananya.conversations(); // everything of hers, any agent\n * ```\n *\n * WHAT NAMING AN END USER DOES, exactly. `start({ endUserId })` labels the\n * conversation so it can be listed back to them, and it decides whose account\n * a connection to the end user's account uses: this person's, for that app,\n * and nobody else's. The grant is the agent's setup, which you can read; it never\n * falls back to the workspace's account or to anybody else's.\n *\n * THE ID IS YOURS. A row id from your database, opaque to us, and we never\n * authenticate it. We are not an identity provider and do not want to be. It\n * also means passing the wrong one hands that person somebody else's mailbox,\n * which is a sharper consequence than the same mistake has for a chat list.\n *\n * Holding one makes NO request.\n */\nexport class EndUser {\n\treadonly id: string;\n\treadonly #http: Http;\n\n\tconstructor(http: Http, id: string) {\n\t\tthis.#http = http;\n\t\tthis.id = id;\n\t}\n\n\tprivate get base(): string {\n\t\treturn `/v1/end-users/${encodeURIComponent(this.id)}/accounts`;\n\t}\n\n\t/**\n\t * This person's own accounts: the \"end user's account\" that a connection\n\t * built with `Connection.endUserAccount(app)` uses.\n\t *\n\t * Connected ONCE, on the app's own page. After that the account is theirs\n\t * and stays theirs: every conversation of theirs uses it, with any agent\n\t * whose setup asks for the end user's account of that app, and nobody is\n\t * sent through a sign-in again per thread. Nothing is attached per\n\t * conversation.\n\t *\n\t * An agent never reaches these any other way: not through the workspace's\n\t * own account of the same app, and not in another person's conversation.\n\t */\n\treadonly accounts = {\n\t\t/** Begin connecting one of their accounts. Returns it, still `pending`,\n\t\t * and the url to send them to. It is an ordinary `Account`:\n\t\t * `account.waitUntilConnected()` tells you when they are done, and\n\t\t * `ws.account(id)` reaches it later. `conversation.accountsNeeded()`\n\t\t * hands you the same kind of link for whatever a conversation is still\n\t\t * missing. */\n\t\tconnect: async (input: { app: AppId }): Promise<{ account: Account; url: string }> => {\n\t\t\t// FIELDS PICKED: the person comes from the path, never from the body.\n\t\t\tconst res = await this.#http.post<{ account?: AccountData; url: string }>(`${this.base}/connect`, {\n\t\t\t\tapp: input.app,\n\t\t\t});\n\t\t\tconst account = accountIn(res, `${this.base}/connect`);\n\t\t\treturn { account: new Account(this.#http, account.id, account), url: res.url };\n\t\t},\n\n\t\t/** Theirs alone. The agent creators' accounts are not here:\n\t\t * `ws.accounts.list()` is the view that shows those. */\n\t\tlist: async (): Promise<Account[]> => {\n\t\t\tconst res = await this.#http.get<{ accounts: AccountData[] }>(this.base);\n\t\t\treturn (res.accounts ?? []).map((a) => new Account(this.#http, a.id, a));\n\t\t},\n\n\t\t/**\n\t\t * Disconnect every account they connected, in one call: what\n\t\t * off-boarding calls, so it is not a loop the caller has to remember to\n\t\t * write. Every conversation of theirs stops reaching those apps from the\n\t\t * next turn, and nothing is kept. Returns how many were disconnected.\n\t\t */\n\t\tdisconnectAll: async (): Promise<{ disconnected: number }> => {\n\t\t\tconst res = await this.#http.delete<{ disconnected?: number }>(this.base);\n\t\t\treturn { disconnected: res?.disconnected ?? 0 };\n\t\t},\n\t};\n\n\t/**\n\t * Credentials that belong to THIS PERSON: their API key for a system you\n\t * integrate with, their token for a service only they have an account on.\n\t *\n\t * THIS WAS ABSENT UNTIL THERE WAS A WAY TO USE IT. A secret reaches a turn\n\t * only by being ATTACHED, and for a long time it could not be, because\n\t * binding one took its VALUE, and you do not hold the value of a secret the\n\t * platform stored for you. So a per-person secret would have been a surface\n\t * that accepted writes, listed them back, and was read by nothing. It was\n\t * left out rather than shipped looking like a feature.\n\t *\n\t * Secrets are still attached; accounts are not (0.44). A person's account is\n\t * reached through the agent's setup (`Connection.endUserAccount`), so there is\n\t * nothing to attach for it.\n\t *\n\t * `sessionBindings.secretIds` is what closed it, and attaching is still an\n\t * explicit line:\n\t *\n\t * ```ts\n\t * const ananya = ws.endUser(row.userId);\n\t * const key = await ananya.secrets.create({ name: 'ZENDESK_TOKEN', value: token });\n\t *\n\t * const conversation = await agent.start({ endUserId: ananya.id });\n\t * await conversation.attach(key); // EXPLICIT. Nothing is implied.\n\t * ```\n\t *\n\t * TWO THINGS THE PLATFORM ENFORCES, neither of which you can turn off:\n\t * the agent must DECLARE that secret name at session scope, so attaching by\n\t * id is not a way around the allowlist; and a secret belonging to one end\n\t * user can only be attached to a conversation launched for that same person,\n\t * so one mistyped id cannot hand Ananya's key to somebody else's turn.\n\t * Both are checked again at every tool call, not only when you attach.\n\t *\n\t * THE CONVERSATION FOLLOWS THE SECRET. It keeps a pointer, never a copy, so\n\t * when your app gets a new token for this person, `key.update(newToken)`\n\t * reaches every conversation it is attached to on the next call, and\n\t * `key.delete()` stops them all at once.\n\t */\n\treadonly secrets = {\n\t\t/** Store a credential for this person. The value is encrypted on arrival\n\t\t * and never handed back, which is why attaching uses the id. */\n\t\tcreate: async (input: {\n\t\t\tname: string;\n\t\t\tvalue: string;\n\t\t\tdescription?: string;\n\t\t\tagentId?: string;\n\t\t\t/** The only hosts a tool may send it to, checked at every call of a\n\t\t\t * conversation it is attached to. Left out, it goes only to the host\n\t\t\t * the agent's tool writes out in full. */\n\t\t\tallowedHosts?: string[];\n\t\t}): Promise<Secret> => {\n\t\t\t// FIELDS PICKED, never the input object forwarded. Removing a field\n\t\t\t// from a type does not stop a JavaScript caller sending it, and\n\t\t\t// forwarding wholesale is how `endUserId` kept reaching the API after\n\t\t\t// it had supposedly been removed.\n\t\t\tconst res = await this.#http.post<{ secret?: SecretMeta } & SecretMeta>('/v1/secrets', {\n\t\t\t\tname: input.name,\n\t\t\t\tvalue: input.value,\n\t\t\t\tendUserId: this.id,\n\t\t\t\t...(input.description !== undefined && { description: input.description }),\n\t\t\t\t...(input.agentId !== undefined && { agentId: input.agentId }),\n\t\t\t\t...(input.allowedHosts !== undefined && { allowedHosts: input.allowedHosts }),\n\t\t\t});\n\t\t\tconst meta = res.secret ?? res;\n\t\t\treturn new Secret(this.#http, meta.id, meta);\n\t\t},\n\t\t/** This person's secrets, values excluded. The workspace's own are not in\n\t\t * here: `ws.secrets.list()` answers that. */\n\t\tlist: async (): Promise<Secret[]> => {\n\t\t\tconst res = await this.#http.get<{ secrets: SecretMeta[] }>('/v1/secrets', {\n\t\t\t\tend_user_id: this.id,\n\t\t\t});\n\t\t\treturn (res.secrets ?? []).map((m) => new Secret(this.#http, m.id, m));\n\t\t},\n\t};\n\n\t/**\n\t * Everything this person has said, ACROSS EVERY AGENT, newest first.\n\t *\n\t * `agent.conversations({ endUser })` answers the narrower question, one agent\n\t * at a time. This is the one an application renders as \"your chats\", and it\n\t * is the only listing in this SDK with a real cursor: pass `before` from the\n\t * previous page to keep going, rather than being capped at 200.\n\t */\n\tasync conversations(options: { limit?: number; before?: string } = {}): Promise<Conversation[]> {\n\t\tconst res = await this.#http.get<{ conversations: AgentConversationData[] }>('/v1/conversations', {\n\t\t\tend_user_id: this.id,\n\t\t\t...(options.limit !== undefined && { limit: options.limit }),\n\t\t\t...(options.before && { before: options.before }),\n\t\t});\n\t\treturn (res.conversations ?? []).map((c) => new Conversation(this.#http, c.id, c));\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"end-user.js","sourceRoot":"","sources":["../src/end-user.ts"],"names":[],"mappings":"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","sourcesContent":["// One of YOUR end users: a person your application serves, who never signs in here.\n\nimport { Account, accountIn } from './account.ts';\nimport { Secret } from './secret.ts';\nimport { Conversation } from './conversation.ts';\nimport type { Http } from './http.ts';\nimport type { AppId } from './apps.generated.ts';\nimport type { AccountData, AgentConversationData, MemoryData, SecretMeta } from './types.ts';\n\n/**\n * One of YOUR end users, of ONE agent, as this platform sees them.\n *\n * EACH AGENT IS ITS OWN APP, WITH ITS OWN END USERS. The same id on two agents is\n * two different people, with separate accounts, secrets and conversations. A\n * person using two of your agents signs in to each. There is no workspace-wide\n * end user, and no way to erase one, because the same id on another agent may be\n * someone else.\n *\n * WHY THE NAME IS `EndUser` AND NOT `User`. There are two populations of people\n * in this product, and calling both of them \"user\" was a bug waiting to be\n * written:\n *\n * | | workspace member | END USER |\n * |---|---|---|\n * | who | your colleague, on a seat | the person your application serves |\n * | belongs to | the workspace | one agent |\n * | signs in to this platform | yes | NEVER |\n * | who issues the id | we do | YOUR database |\n * | do we authenticate it | yes | no, deliberately |\n * | in this SDK | `ws.members()` | `agent.endUser(id)` |\n *\n * They were both spelled `userId`, so `ws.members()` handed you an id that\n * `agent.start()` would accept without complaint and label a conversation with\n * a teammate's internal platform id. It could never have errored, because an\n * end-user id is never checked against anything. The two names now make that\n * call impossible to write by accident.\n *\n * NOT `Customer`, which was tried and reverted. Two reasons. \"Customer\" already\n * means the party that BUYS this platform, in our own strategy documents and in\n * `subscriptions.stripe_customer_id`, so the word points the other way. And it\n * is wrong for the common case: an enterprise deploying an internal workflow\n * agent serves its own EMPLOYEES, who are not anybody's customers.\n *\n * WHY THIS OBJECT EXISTS. You are building an application for many people.\n * Ananya has her own Gmail, her own conversations and her own history, and so\n * do the other ten thousand. Every call you make is on behalf of one of them.\n *\n * Without this, the person is an argument: `endUserId` threaded through\n * `accounts.connect`, `secrets.create`, `conversations` and `start`, and\n * forgotten in exactly one of them one day. With it, you say who once and the\n * rest follows:\n *\n * ```ts\n * // once, in the agent's setup: each person uses their own Gmail\n * await agent.connections.add(Connection.endUserAccount(App.GMAIL));\n *\n * const ananya = agent.endUser(row.userId); // no request\n * const { url } = await ananya.accounts.connect({ app: App.GMAIL });\n * showToUser(url); // she signs in ONCE, for this agent\n *\n * const conversation = await agent.start({ endUserId: ananya.id });\n * await conversation.ask('what did I miss this morning?');\n *\n * await ananya.conversations(); // everything of hers, with this agent\n * await ananya.erase(); // she left: all of it, on this agent\n * ```\n *\n * WHAT NAMING AN END USER DOES, exactly. `start({ endUserId })` labels the\n * conversation so it can be listed back to them, and it decides whose account\n * a connection to the end user's account uses: this person's, on this agent, for\n * that app, and nobody else's. The grant is the agent's setup, which you can read;\n * it never falls back to the workspace's account, or to anybody else's.\n *\n * THE ID IS YOURS. A row id from your database, opaque to us, and we never\n * authenticate it. We are not an identity provider and do not want to be. It\n * also means passing the wrong one hands that person somebody else's mailbox,\n * which is a sharper consequence than the same mistake has for a chat list.\n *\n * Holding one makes NO request.\n */\nexport class EndUser {\n\treadonly id: string;\n\t/** The agent this person belongs to, as you addressed it. */\n\treadonly agentId: string;\n\treadonly #http: Http;\n\n\tconstructor(http: Http, agentId: string, id: string) {\n\t\tthis.#http = http;\n\t\tthis.agentId = agentId;\n\t\tthis.id = id;\n\t}\n\n\tprivate get base(): string {\n\t\treturn `/v1/agents/${encodeURIComponent(this.agentId)}/end-users/${encodeURIComponent(this.id)}`;\n\t}\n\n\t/**\n\t * This person's own accounts on this agent: the \"end user's account\" that a\n\t * connection built with `Connection.endUserAccount(app)` uses.\n\t *\n\t * Connected ONCE, on the app's own page. After that the account is theirs\n\t * on this agent and stays theirs: every conversation of theirs with this agent\n\t * uses it, and nobody is sent through a sign-in again per thread. Nothing is\n\t * attached per conversation.\n\t *\n\t * An agent never reaches these any other way: not through the workspace's\n\t * own account of the same app, not in another person's conversation, and not\n\t * on another agent. The same id on another agent is another person, who signs\n\t * in there.\n\t */\n\treadonly accounts = {\n\t\t/** Begin connecting one of their accounts. Returns it, still `pending`,\n\t\t * and the url to send them to. It is an ordinary `Account`:\n\t\t * `account.waitUntilConnected()` tells you when they are done, and\n\t\t * `ws.account(id)` reaches it later. `conversation.accountsNeeded()`\n\t\t * hands you the same kind of link for whatever a conversation is still\n\t\t * missing. */\n\t\tconnect: async (input: { app: AppId }): Promise<{ account: Account; url: string }> => {\n\t\t\t// FIELDS PICKED: the agent and the person come from the path, never from the body.\n\t\t\tconst res = await this.#http.post<{ account?: AccountData; url: string }>(`${this.base}/accounts/connect`, {\n\t\t\t\tapp: input.app,\n\t\t\t});\n\t\t\tconst account = accountIn(res, `${this.base}/accounts/connect`);\n\t\t\treturn { account: new Account(this.#http, account.id, account), url: res.url };\n\t\t},\n\n\t\t/** Theirs on this agent alone. The agent creators' accounts are not here:\n\t\t * `ws.accounts.list()` is the view that shows those. */\n\t\tlist: async (): Promise<Account[]> => {\n\t\t\tconst res = await this.#http.get<{ accounts: AccountData[] }>(`${this.base}/accounts`);\n\t\t\treturn (res.accounts ?? []).map((a) => new Account(this.#http, a.id, a));\n\t\t},\n\n\t\t/**\n\t\t * Disconnect every account they connected on this agent, in one call, so it\n\t\t * is not a loop the caller has to remember to write. Every conversation of\n\t\t * theirs with this agent stops reaching those apps from the next turn, and\n\t\t * nothing is kept. Returns how many were disconnected. To remove everything\n\t\t * about them, use `erase()`.\n\t\t */\n\t\tdisconnectAll: async (): Promise<{ disconnected: number }> => {\n\t\t\tconst res = await this.#http.delete<{ disconnected?: number }>(`${this.base}/accounts`);\n\t\t\treturn { disconnected: res?.disconnected ?? 0 };\n\t\t},\n\t};\n\n\t/**\n\t * Credentials that belong to THIS PERSON: their API key for a system you\n\t * integrate with, their token for a service only they have an account on.\n\t *\n\t * THIS WAS ABSENT UNTIL THERE WAS A WAY TO USE IT. A secret reaches a turn\n\t * only by being ATTACHED, and for a long time it could not be, because\n\t * binding one took its VALUE, and you do not hold the value of a secret the\n\t * platform stored for you. So a per-person secret would have been a surface\n\t * that accepted writes, listed them back, and was read by nothing. It was\n\t * left out rather than shipped looking like a feature.\n\t *\n\t * Secrets are still attached; accounts are not (0.44). A person's account is\n\t * reached through the agent's setup (`Connection.endUserAccount`), so there is\n\t * nothing to attach for it.\n\t *\n\t * `sessionBindings.secretIds` is what closed it, and attaching is still an\n\t * explicit line:\n\t *\n\t * ```ts\n\t * const ananya = agent.endUser(row.userId);\n\t * const key = await ananya.secrets.create({ name: 'ZENDESK_TOKEN', value: token });\n\t *\n\t * const conversation = await agent.start({ endUserId: ananya.id });\n\t * await conversation.attach(key); // EXPLICIT. Nothing is implied.\n\t * ```\n\t *\n\t * TWO THINGS THE PLATFORM ENFORCES, neither of which you can turn off:\n\t * the agent must DECLARE that secret name at session scope, so attaching by\n\t * id is not a way around the allowlist; and a secret belonging to one end\n\t * user can only be attached to a conversation launched for that same person\n\t * with this same agent, so one mistyped id cannot hand Ananya's key to somebody\n\t * else's turn.\n\t * Both are checked again at every tool call, not only when you attach.\n\t *\n\t * THE CONVERSATION FOLLOWS THE SECRET. It keeps a pointer, never a copy, so\n\t * when your app gets a new token for this person, `key.update(newToken)`\n\t * reaches every conversation it is attached to on the next call, and\n\t * `key.delete()` stops them all at once.\n\t */\n\treadonly secrets = {\n\t\t/** Store a credential for this person. The value is encrypted on arrival\n\t\t * and never handed back, which is why attaching uses the id. */\n\t\tcreate: async (input: {\n\t\t\tname: string;\n\t\t\tvalue: string;\n\t\t\tdescription?: string;\n\t\t\t/** The only hosts a tool may send it to, checked at every call of a\n\t\t\t * conversation it is attached to. Left out, it goes only to the host\n\t\t\t * the agent's tool writes out in full. */\n\t\t\tallowedHosts?: string[];\n\t\t}): Promise<Secret> => {\n\t\t\t// FIELDS PICKED, never the input object forwarded. Removing a field\n\t\t\t// from a type does not stop a JavaScript caller sending it, and\n\t\t\t// forwarding wholesale is how `endUserId` kept reaching the API after\n\t\t\t// it had supposedly been removed.\n\t\t\tconst res = await this.#http.post<{ secret?: SecretMeta } & SecretMeta>('/v1/secrets', {\n\t\t\t\tname: input.name,\n\t\t\t\tvalue: input.value,\n\t\t\t\tendUserId: this.id,\n\t\t\t\tagentId: this.agentId,\n\t\t\t\t...(input.description !== undefined && { description: input.description }),\n\t\t\t\t...(input.allowedHosts !== undefined && { allowedHosts: input.allowedHosts }),\n\t\t\t});\n\t\t\tconst meta = res.secret ?? res;\n\t\t\treturn new Secret(this.#http, meta.id, meta);\n\t\t},\n\t\t/** This person's secrets on this agent, values excluded. The workspace's own\n\t\t * are not in here: `ws.secrets.list()` answers that. */\n\t\tlist: async (): Promise<Secret[]> => {\n\t\t\tconst res = await this.#http.get<{ secrets: SecretMeta[] }>('/v1/secrets', {\n\t\t\t\tend_user_id: this.id,\n\t\t\t\tagentId: this.agentId,\n\t\t\t});\n\t\t\treturn (res.secrets ?? []).map((m) => new Secret(this.#http, m.id, m));\n\t\t},\n\t};\n\n\t/**\n\t * What this agent remembers about them. Nothing here runs during a chat: this\n\t * is for your own screens and tools. Your whole team may read and edit it, and\n\t * an API key may.\n\t *\n\t * Nothing in it is secret from them: the agent can repeat any line if they ask.\n\t */\n\treadonly memory = {\n\t\t/** Their memory. Empty text if there is none yet. */\n\t\tget: (): Promise<MemoryData> => this.#http.get<MemoryData>(`${this.base}/memory`),\n\t\t/**\n\t\t * Replace it, one fact per line, at most 30 lines. Refused if it holds a card,\n\t\t * key or id number, or is too long. Chats from before this save can no longer\n\t\t * change it.\n\t\t */\n\t\tset: (text: string): Promise<MemoryData> => this.#http.put<MemoryData>(`${this.base}/memory`, { text }),\n\t\t/** Delete it. No copy is kept, and their earlier chats cannot bring it back. A later chat can start a new one. */\n\t\tdelete: async (): Promise<void> => {\n\t\t\tawait this.#http.delete(`${this.base}/memory`);\n\t\t},\n\t\t/** They asked to stop: delete it and keep nothing more about them. `false` undoes this, only if they ask. */\n\t\tstop: (stopped = true): Promise<MemoryData> => this.#http.put<MemoryData>(`${this.base}/memory/stop`, { stopped }),\n\t};\n\n\t/**\n\t * Everything this person has said to this agent, newest first. Pass `before`\n\t * from the previous page to keep going, rather than being capped at 200.\n\t */\n\tasync conversations(options: { limit?: number; before?: string } = {}): Promise<Conversation[]> {\n\t\tconst res = await this.#http.get<{ conversations: AgentConversationData[] }>('/v1/conversations', {\n\t\t\tagentId: this.agentId,\n\t\t\tend_user_id: this.id,\n\t\t\t...(options.limit !== undefined && { limit: options.limit }),\n\t\t\t...(options.before && { before: options.before }),\n\t\t});\n\t\treturn (res.conversations ?? []).map((c) => new Conversation(this.#http, c.id, c));\n\t}\n\n\t/**\n\t * Delete everything about them on this agent, in one call: their accounts\n\t * (signed out at the app first), their secrets, their conversations, the wakeups\n\t * those conversations set, and what the agent remembers about them. What off-boarding and an erasure request call.\n\t *\n\t * This agent only. The same id on another agent may be someone else, so there\n\t * is no workspace-wide erase: if one person uses two of your agents, erase them\n\t * from each. A schedule you configured on the agent to name them stays, because\n\t * it is your setup. A project's conversations belong to the project and are\n\t * deleted by id.\n\t *\n\t * Safe to call again. An account that cannot be signed out fails the call with\n\t * the rest still in place, so a credential is never orphaned. A turn still running\n\t * when this lands can write after it, and a second call clears what it left.\n\t * Returns how many of each went.\n\t */\n\tasync erase(): Promise<{ accounts: number; secrets: number; conversations: number }> {\n\t\tconst total = { accounts: 0, secrets: 0, conversations: 0 };\n\t\tlet more = true;\n\t\twhile (more) {\n\t\t\tconst res = await this.#http.delete<{ accounts?: number; secrets?: number; conversations?: number; more?: boolean }>(this.base);\n\t\t\ttotal.accounts += res?.accounts ?? 0;\n\t\t\ttotal.secrets += res?.secrets ?? 0;\n\t\t\ttotal.conversations += res?.conversations ?? 0;\n\t\t\tmore = res?.more === true;\n\t\t}\n\t\treturn total;\n\t}\n}\n"]}
|
package/index.d.ts
CHANGED
|
@@ -17,5 +17,5 @@ export { loadAgentDir } from './load-agent-dir.ts';
|
|
|
17
17
|
export { loadManagerTemplate } from './templates.ts';
|
|
18
18
|
export type { Turn } from './turn.ts';
|
|
19
19
|
export type { ClientOptions } from './http.ts';
|
|
20
|
-
export type { AppTool, AccountData, AccountNeeded, AccountStatus, AgentConnection, AgentConversationData, AgentData, AgentDraft, AgentFields, AgentStatus, WebsiteChatAppearance, Attachment, Bindings, ConnectionStatus, Credits, Guardrails, DatabaseColumn, DatabaseData, DatabaseEngine, DatabaseFields, DatabaseLogin, DatabaseTable, DatabaseTestResult, DatabaseTls, DatabaseUsedBy, FileEntry, Filesystem, Grade, HttpTool, HttpToolParam, McpServer, ProjectAgent, Message, Parameter, ProjectConversationData, ProjectData, ProjectFields, Requirement, Scope, SeatPlan, SecretMeta, SecretRequirement, Step, Trigger, WebhookDelivery, WebhookVerify, TriggerTarget, TurnEvent, Widget, WidgetPart, UsedBy, WebsiteChat, WebsiteChatAccess, Workflow, WorkspaceInfo, WorkspaceMember, } from './types.ts';
|
|
20
|
+
export type { AppTool, AccountData, AccountNeeded, AccountStatus, AgentConnection, AgentConversationData, AgentData, AgentDraft, AgentFields, AgentStatus, WebsiteChatAppearance, Attachment, Bindings, ConnectionStatus, Credits, Guardrails, MemoryData, MemorySettings, DatabaseColumn, DatabaseData, DatabaseEngine, DatabaseFields, DatabaseLogin, DatabaseTable, DatabaseTestResult, DatabaseTls, DatabaseUsedBy, FileEntry, Filesystem, Grade, HttpTool, HttpToolParam, McpServer, ProjectAgent, Message, SentAttachment, Parameter, ProjectConversationData, ProjectData, ProjectFields, Requirement, Scope, SeatPlan, SecretMeta, SecretRequirement, Step, Trigger, WebhookDelivery, WebhookVerify, TriggerTarget, TurnEvent, Widget, WidgetPart, UsedBy, WebsiteChat, WebsiteChatAccess, Workflow, WorkspaceInfo, WorkspaceMember, } from './types.ts';
|
|
21
21
|
export { placeWidgets, type ReplyPiece } from './widgets.ts';
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,EAAE;AACF,0DAA0D;AAC1D,EAAE;AACF,6DAA6D;AAC7D,EAAE;AACF,yCAAyC;AACzC,2CAA2C;AAC3C,8BAA8B;AAC9B,8EAA8E;AAC9E,QAAQ;AACR,uEAAuE;AACvE,2EAA2E;AAC3E,EAAE;AACF,yDAAyD;AAEzD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAgE,MAAM,kBAAkB,CAAC;AAC5G,OAAO,EAAE,KAAK,EAAqB,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,2EAA2E;AAC3E,iFAAiF;AACjF,OAAO,EACN,UAAU,GAGV,MAAM,iBAAiB,CAAC;AACzB,6EAA6E;AAC7E,wEAAwE;AACxE,OAAO,EAAE,GAAG,EAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAA4D,MAAM,mBAAmB,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAA4B,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC9D,yEAAyE;AACzE,8EAA8E;AAC9E,6EAA6E;AAC7E,2DAA2D;AAC3D,OAAO,EACN,WAAW,EACX,WAAW,EACX,cAAc,EACd,WAAW,EACX,QAAQ,EACR,YAAY,GASZ,MAAM,mBAAmB,CAAC;AAC3B,4EAA4E;AAC5E,kEAAkE;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,+EAA+E;AAC/E,6EAA6E;AAC7E,2BAA2B;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,EAAE;AACF,0DAA0D;AAC1D,EAAE;AACF,6DAA6D;AAC7D,EAAE;AACF,yCAAyC;AACzC,2CAA2C;AAC3C,8BAA8B;AAC9B,8EAA8E;AAC9E,QAAQ;AACR,uEAAuE;AACvE,2EAA2E;AAC3E,EAAE;AACF,yDAAyD;AAEzD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAgE,MAAM,kBAAkB,CAAC;AAC5G,OAAO,EAAE,KAAK,EAAqB,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,2EAA2E;AAC3E,iFAAiF;AACjF,OAAO,EACN,UAAU,GAGV,MAAM,iBAAiB,CAAC;AACzB,6EAA6E;AAC7E,wEAAwE;AACxE,OAAO,EAAE,GAAG,EAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAA4D,MAAM,mBAAmB,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAA4B,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC9D,yEAAyE;AACzE,8EAA8E;AAC9E,6EAA6E;AAC7E,2DAA2D;AAC3D,OAAO,EACN,WAAW,EACX,WAAW,EACX,cAAc,EACd,WAAW,EACX,QAAQ,EACR,YAAY,GASZ,MAAM,mBAAmB,CAAC;AAC3B,4EAA4E;AAC5E,kEAAkE;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,+EAA+E;AAC/E,6EAA6E;AAC7E,2BAA2B;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAgErD,OAAO,EAAE,YAAY,EAAmB,MAAM,cAAc,CAAC","sourcesContent":["// @cerebro-labs/agentnava-sdk\n//\n// Configure an agent, start a conversation, work with it.\n//\n// import { AgentNava } from '@cerebro-labs/agentnava-sdk';\n//\n// const ws = AgentNava.getWorkspace();\n// const agent = await ws.agents.create({\n// name: 'Refund checker',\n// instructions: 'Decide whether a late delivery qualifies for a refund.',\n// });\n// const conversation = await agent.start({ endUserId: 'u_ananya' });\n// console.log(await conversation.ask('Order 4471 was nine days late.'));\n//\n// The reference this implements is design/sdk-design.md.\n\nexport { AgentNava, Workspace } from './workspace.ts';\nexport { PartnerApp, type PartnerAppOptions, type ExchangedCode, type CreditGrant } from './partner-app.ts';\nexport { Agent, type StartOptions } from './agent.ts';\nexport { Account } from './account.ts';\n// Builds one entry of an agent's setup: an app, and whose account. NOT the\n// 0.43 `Connection`, which was a handle on a signed-in account and is `Account`.\nexport {\n\tConnection,\n\ttype CreatorAccountConnection,\n\ttype EndUserAccountConnection,\n} from './connection.ts';\n// Every app the platform can connect, as constants: `App.GMAIL === 'gmail'`.\n// Generated from the connections catalog; any plain string still works.\nexport { App, type AppId } from './apps.generated.ts';\nexport { Secret } from './secret.ts';\nexport { EndUser } from './end-user.ts';\nexport { Conversation, type AskOptions, type AttachOptions, type FileUrlOptions } from './conversation.ts';\nexport { KnowledgeBase } from './knowledge-base.ts';\nexport { Database } from './database.ts';\nexport { Project, type ProjectStartOptions } from './project.ts';\nexport { AgentNavaError, SecretHostNotAllowed } from './errors.ts';\nexport { loadWorkflows, parseWorkflow } from './workflows.ts';\n// Draft an agent's tools from whatever a company already has: an OpenAPI\n// document, a Postman collection, or a working curl command. Runs entirely on\n// your machine: nothing about the source is sent to AgentNava, which matters\n// because those files routinely contain a live credential.\nexport {\n\timportTools,\n\tfromOpenApi,\n\tfromOpenApiUrl,\n\tfromPostman,\n\tfromCurl,\n\ttoolNameFrom,\n\ttype ImportSource,\n\ttype ImportOptions,\n\ttype ImportedTools,\n\ttype ImportedSecret,\n\ttype ImportWarning,\n\ttype ImportWarningKind,\n\ttype OpenApiDocument,\n\ttype PostmanCollection,\n} from './import-tools.ts';\n// Reads a whole Claude-Code-shaped agent directory (AGENT.md + workflows/ +\n// mcp-servers.json ...) into the fields ws.agents.create() takes.\nexport { loadAgentDir } from './load-agent-dir.ts';\n// The platform's built-in project-manager configuration. apps/api imports this\n// through the './templates' subpath; re-exported here so the package has one\n// surface rather than two.\nexport { loadManagerTemplate } from './templates.ts';\nexport type { Turn } from './turn.ts';\nexport type { ClientOptions } from './http.ts';\nexport type {\n\tAppTool,\n\tAccountData,\n\tAccountNeeded,\n\tAccountStatus,\n\tAgentConnection,\n\tAgentConversationData,\n\tAgentData,\n\tAgentDraft,\n\tAgentFields,\n\tAgentStatus,\n\tWebsiteChatAppearance,\n\tAttachment,\n\tBindings,\n\tConnectionStatus,\n\tCredits,\n\tGuardrails,\n\tMemoryData,\n\tMemorySettings,\n\tDatabaseColumn,\n\tDatabaseData,\n\tDatabaseEngine,\n\tDatabaseFields,\n\tDatabaseLogin,\n\tDatabaseTable,\n\tDatabaseTestResult,\n\tDatabaseTls,\n\tDatabaseUsedBy,\n\tFileEntry,\n\tFilesystem,\n\tGrade,\n\tHttpTool,\n\tHttpToolParam,\n\tMcpServer,\n\tProjectAgent,\n\tMessage,\n\tSentAttachment,\n\tParameter,\n\tProjectConversationData,\n\tProjectData,\n\tProjectFields,\n\tRequirement,\n\tScope,\n\tSeatPlan,\n\tSecretMeta,\n\tSecretRequirement,\n\tStep,\n\tTrigger,\n\tWebhookDelivery,\n\tWebhookVerify,\n\tTriggerTarget,\n\tTurnEvent,\n\tWidget,\n\tWidgetPart,\n\tUsedBy,\n\tWebsiteChat,\n\tWebsiteChatAccess,\n\tWorkflow,\n\tWorkspaceInfo,\n\tWorkspaceMember,\n} from './types.ts';\nexport { placeWidgets, type ReplyPiece } from './widgets.ts';\n"]}
|
package/package.json
CHANGED
package/react.d.ts
CHANGED
|
@@ -34,7 +34,9 @@ export interface ReplyViewProps extends Omit<WidgetViewProps, 'widget' | 'classN
|
|
|
34
34
|
renderText?: (text: string) => ReactNode;
|
|
35
35
|
className?: string;
|
|
36
36
|
}
|
|
37
|
-
/** One widget, drawn from its root part. Draws nothing when there is no root
|
|
37
|
+
/** One widget, drawn from its root part. Draws nothing when there is no root
|
|
38
|
+
* yet, or nothing in it to draw: a container that lists none of its parts
|
|
39
|
+
* drew an empty frame (Complexity, 2026-11-02, a root Column with no children). */
|
|
38
40
|
export declare function WidgetView(props: WidgetViewProps): import("react/jsx-runtime").JSX.Element | null;
|
|
39
41
|
/** A whole reply: its words, with each widget drawn where it sits. */
|
|
40
42
|
export declare function ReplyView({ text, widgets, renderText, className, ...widgetProps }: ReplyViewProps): import("react/jsx-runtime").JSX.Element;
|
package/react.js
CHANGED
|
@@ -275,7 +275,23 @@ function draw(id, ctx) {
|
|
|
275
275
|
const own = ctx.props.parts?.[part.component];
|
|
276
276
|
return own ? own({ part, children: kids, onAsk: ctx.props.onAsk }) : defaultPart(part, kids, ctx);
|
|
277
277
|
}
|
|
278
|
-
/**
|
|
278
|
+
/** Whether a part draws anything: a part that is not a container does; a
|
|
279
|
+
* container only through a child that does (a Card through its picture too).
|
|
280
|
+
* A part listed twice, or a loop, counts once. */
|
|
281
|
+
function drawsSomething(id, byId, seen = new Set()) {
|
|
282
|
+
const part = byId.get(id);
|
|
283
|
+
if (!part || seen.has(id))
|
|
284
|
+
return false;
|
|
285
|
+
seen.add(id);
|
|
286
|
+
if (!CONTAINERS.has(part.component))
|
|
287
|
+
return true;
|
|
288
|
+
if (part.component === 'Card' && part.image)
|
|
289
|
+
return true;
|
|
290
|
+
return list(part.children).some((k) => typeof k === 'string' && drawsSomething(k, byId, seen));
|
|
291
|
+
}
|
|
292
|
+
/** One widget, drawn from its root part. Draws nothing when there is no root
|
|
293
|
+
* yet, or nothing in it to draw: a container that lists none of its parts
|
|
294
|
+
* drew an empty frame (Complexity, 2026-11-02, a root Column with no children). */
|
|
279
295
|
export function WidgetView(props) {
|
|
280
296
|
const { widget, currency = 'USD', locale, allowUrl } = props;
|
|
281
297
|
const byId = new Map();
|
|
@@ -283,7 +299,7 @@ export function WidgetView(props) {
|
|
|
283
299
|
if (p && typeof p === 'object' && typeof p.id === 'string' && typeof p.component === 'string' && !byId.has(p.id))
|
|
284
300
|
byId.set(p.id, p);
|
|
285
301
|
}
|
|
286
|
-
if (!
|
|
302
|
+
if (!drawsSomething('root', byId))
|
|
287
303
|
return null;
|
|
288
304
|
let moneyFormat;
|
|
289
305
|
try {
|