@mondaydotcomorg/atp-client 0.19.5 → 0.19.7
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/dist/client.d.ts +23 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +26 -5
- package/dist/client.js.map +1 -1
- package/dist/core/api-operations.d.ts +4 -2
- package/dist/core/api-operations.d.ts.map +1 -1
- package/dist/core/api-operations.js +25 -1
- package/dist/core/api-operations.js.map +1 -1
- package/dist/core/execution-operations.d.ts +4 -2
- package/dist/core/execution-operations.d.ts.map +1 -1
- package/dist/core/execution-operations.js +60 -40
- package/dist/core/execution-operations.js.map +1 -1
- package/dist/core/in-process-session.d.ts +96 -0
- package/dist/core/in-process-session.d.ts.map +1 -0
- package/dist/core/in-process-session.js +175 -0
- package/dist/core/in-process-session.js.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/provenance-registry.d.ts +3 -0
- package/dist/core/provenance-registry.d.ts.map +1 -1
- package/dist/core/provenance-registry.js +12 -6
- package/dist/core/provenance-registry.js.map +1 -1
- package/dist/core/session.d.ts +24 -1
- package/dist/core/session.d.ts.map +1 -1
- package/dist/core/session.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +8 -5
- package/src/client.ts +47 -7
- package/src/core/api-operations.ts +35 -3
- package/src/core/execution-operations.ts +69 -45
- package/src/core/in-process-session.ts +294 -0
- package/src/core/index.ts +1 -0
- package/src/core/provenance-registry.ts +14 -6
- package/src/core/session.ts +20 -1
- package/src/index.ts +2 -0
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import type { ExecutionResult, ExecutionConfig } from '@mondaydotcomorg/atp-protocol';
|
|
2
2
|
import { ExecutionStatus, CallbackType } from '@mondaydotcomorg/atp-protocol';
|
|
3
3
|
import { log } from '@mondaydotcomorg/atp-runtime';
|
|
4
|
-
import type {
|
|
4
|
+
import type { ISession } from './session.js';
|
|
5
|
+
import type { InProcessSession } from './in-process-session.js';
|
|
5
6
|
import type { ServiceProviders } from './service-providers';
|
|
6
7
|
import { ClientCallbackError } from '../errors.js';
|
|
7
8
|
import { ProvenanceTokenRegistry } from './provenance-registry.js';
|
|
8
9
|
|
|
9
10
|
export class ExecutionOperations {
|
|
10
|
-
private session:
|
|
11
|
+
private session: ISession;
|
|
12
|
+
private inProcessSession?: InProcessSession;
|
|
11
13
|
private serviceProviders: ServiceProviders;
|
|
12
14
|
private tokenRegistry: ProvenanceTokenRegistry;
|
|
13
15
|
private lastExecutionConfig: Partial<ExecutionConfig> | null = null;
|
|
14
16
|
|
|
15
|
-
constructor(session:
|
|
17
|
+
constructor(session: ISession, serviceProviders: ServiceProviders, inProcessSession?: InProcessSession) {
|
|
16
18
|
this.session = session;
|
|
19
|
+
this.inProcessSession = inProcessSession;
|
|
17
20
|
this.serviceProviders = serviceProviders;
|
|
18
21
|
this.tokenRegistry = new ProvenanceTokenRegistry();
|
|
19
22
|
}
|
|
@@ -132,24 +135,30 @@ export class ExecutionOperations {
|
|
|
132
135
|
|
|
133
136
|
this.lastExecutionConfig = executionConfig;
|
|
134
137
|
|
|
135
|
-
|
|
136
|
-
const body = JSON.stringify({ code, config: executionConfig });
|
|
137
|
-
const headers = await this.session.prepareHeaders('POST', url, body);
|
|
138
|
+
let result: ExecutionResult;
|
|
138
139
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
140
|
+
if (this.inProcessSession) {
|
|
141
|
+
result = (await this.inProcessSession.execute(code, executionConfig)) as ExecutionResult;
|
|
142
|
+
} else {
|
|
143
|
+
const url = `${this.session.getBaseUrl()}/api/execute`;
|
|
144
|
+
const body = JSON.stringify({ code, config: executionConfig });
|
|
145
|
+
const headers = await this.session.prepareHeaders('POST', url, body);
|
|
144
146
|
|
|
145
|
-
|
|
147
|
+
const response = await fetch(url, {
|
|
148
|
+
method: 'POST',
|
|
149
|
+
headers,
|
|
150
|
+
body,
|
|
151
|
+
});
|
|
146
152
|
|
|
147
|
-
|
|
148
|
-
const error = (await response.json()) as { error: string };
|
|
149
|
-
throw new Error(`Execution failed: ${error.error || response.statusText}`);
|
|
150
|
-
}
|
|
153
|
+
this.session.updateToken(response);
|
|
151
154
|
|
|
152
|
-
|
|
155
|
+
if (!response.ok) {
|
|
156
|
+
const error = (await response.json()) as { error: string };
|
|
157
|
+
throw new Error(`Execution failed: ${error.error || response.statusText}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
result = (await response.json()) as ExecutionResult;
|
|
161
|
+
}
|
|
153
162
|
|
|
154
163
|
if (result.provenanceTokens && result.provenanceTokens.length > 0) {
|
|
155
164
|
for (const { token } of result.provenanceTokens) {
|
|
@@ -383,24 +392,30 @@ export class ExecutionOperations {
|
|
|
383
392
|
async resume(executionId: string, callbackResult: unknown): Promise<ExecutionResult> {
|
|
384
393
|
await this.session.ensureInitialized();
|
|
385
394
|
|
|
386
|
-
|
|
387
|
-
const body = JSON.stringify({ result: callbackResult });
|
|
388
|
-
const headers = await this.session.prepareHeaders('POST', url, body);
|
|
395
|
+
let result: ExecutionResult;
|
|
389
396
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
397
|
+
if (this.inProcessSession) {
|
|
398
|
+
result = (await this.inProcessSession.resume(executionId, callbackResult)) as ExecutionResult;
|
|
399
|
+
} else {
|
|
400
|
+
const url = `${this.session.getBaseUrl()}/api/resume/${executionId}`;
|
|
401
|
+
const body = JSON.stringify({ result: callbackResult });
|
|
402
|
+
const headers = await this.session.prepareHeaders('POST', url, body);
|
|
403
|
+
|
|
404
|
+
const response = await fetch(url, {
|
|
405
|
+
method: 'POST',
|
|
406
|
+
headers,
|
|
407
|
+
body,
|
|
408
|
+
});
|
|
395
409
|
|
|
396
|
-
|
|
410
|
+
this.session.updateToken(response);
|
|
397
411
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
412
|
+
if (!response.ok) {
|
|
413
|
+
const error = (await response.json()) as { error: string };
|
|
414
|
+
throw new Error(`Resume failed: ${error.error || response.statusText}`);
|
|
415
|
+
}
|
|
402
416
|
|
|
403
|
-
|
|
417
|
+
result = (await response.json()) as ExecutionResult;
|
|
418
|
+
}
|
|
404
419
|
|
|
405
420
|
if (result.provenanceTokens && result.provenanceTokens.length > 0) {
|
|
406
421
|
for (const { token } of result.provenanceTokens) {
|
|
@@ -428,24 +443,33 @@ export class ExecutionOperations {
|
|
|
428
443
|
): Promise<ExecutionResult> {
|
|
429
444
|
await this.session.ensureInitialized();
|
|
430
445
|
|
|
431
|
-
|
|
432
|
-
const body = JSON.stringify({ results: batchResults });
|
|
433
|
-
const headers = await this.session.prepareHeaders('POST', url, body);
|
|
446
|
+
let result: ExecutionResult;
|
|
434
447
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
448
|
+
if (this.inProcessSession) {
|
|
449
|
+
result = (await this.inProcessSession.resumeWithBatchResults(
|
|
450
|
+
executionId,
|
|
451
|
+
batchResults
|
|
452
|
+
)) as ExecutionResult;
|
|
453
|
+
} else {
|
|
454
|
+
const url = `${this.session.getBaseUrl()}/api/resume/${executionId}`;
|
|
455
|
+
const body = JSON.stringify({ results: batchResults });
|
|
456
|
+
const headers = await this.session.prepareHeaders('POST', url, body);
|
|
440
457
|
|
|
441
|
-
|
|
458
|
+
const response = await fetch(url, {
|
|
459
|
+
method: 'POST',
|
|
460
|
+
headers,
|
|
461
|
+
body,
|
|
462
|
+
});
|
|
442
463
|
|
|
443
|
-
|
|
444
|
-
const error = (await response.json()) as { error: string };
|
|
445
|
-
throw new Error(`Batch resume failed: ${error.error || response.statusText}`);
|
|
446
|
-
}
|
|
464
|
+
this.session.updateToken(response);
|
|
447
465
|
|
|
448
|
-
|
|
466
|
+
if (!response.ok) {
|
|
467
|
+
const error = (await response.json()) as { error: string };
|
|
468
|
+
throw new Error(`Batch resume failed: ${error.error || response.statusText}`);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
result = (await response.json()) as ExecutionResult;
|
|
472
|
+
}
|
|
449
473
|
|
|
450
474
|
if (result.provenanceTokens && result.provenanceTokens.length > 0) {
|
|
451
475
|
for (const { token } of result.provenanceTokens) {
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import type { ClientToolDefinition } from '@mondaydotcomorg/atp-protocol';
|
|
2
|
+
import type { ISession } from './session.js';
|
|
3
|
+
|
|
4
|
+
interface InProcessServer {
|
|
5
|
+
start(): Promise<void>;
|
|
6
|
+
handleInit(ctx: InProcessRequestContext): Promise<unknown>;
|
|
7
|
+
getDefinitions(ctx?: InProcessRequestContext): Promise<unknown>;
|
|
8
|
+
getRuntimeDefinitions(ctx?: InProcessRequestContext): Promise<string>;
|
|
9
|
+
getInfo(): unknown;
|
|
10
|
+
handleSearch(ctx: InProcessRequestContext): Promise<unknown>;
|
|
11
|
+
handleExplore(ctx: InProcessRequestContext): Promise<unknown>;
|
|
12
|
+
handleExecute(ctx: InProcessRequestContext): Promise<unknown>;
|
|
13
|
+
handleResume(ctx: InProcessRequestContext, executionId: string): Promise<unknown>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface InProcessRequestContext {
|
|
17
|
+
method: string;
|
|
18
|
+
path: string;
|
|
19
|
+
query: Record<string, string>;
|
|
20
|
+
headers: Record<string, string>;
|
|
21
|
+
body: unknown;
|
|
22
|
+
clientId?: string;
|
|
23
|
+
clientToken?: string;
|
|
24
|
+
userId?: string;
|
|
25
|
+
user?: unknown;
|
|
26
|
+
executionId?: string;
|
|
27
|
+
code?: string;
|
|
28
|
+
validation?: unknown;
|
|
29
|
+
result?: unknown;
|
|
30
|
+
error?: Error;
|
|
31
|
+
logger: { debug: () => void; info: () => void; warn: () => void; error: () => void };
|
|
32
|
+
status: number;
|
|
33
|
+
responseBody: unknown;
|
|
34
|
+
throw(status: number, message: string): never;
|
|
35
|
+
assert(condition: boolean, message: string): asserts condition;
|
|
36
|
+
set(header: string, value: string): void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class InProcessSession implements ISession {
|
|
40
|
+
private server: InProcessServer;
|
|
41
|
+
private clientId?: string;
|
|
42
|
+
private clientToken?: string;
|
|
43
|
+
private initialized: boolean = false;
|
|
44
|
+
private initPromise?: Promise<void>;
|
|
45
|
+
|
|
46
|
+
constructor(server: InProcessServer) {
|
|
47
|
+
this.server = server;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async init(
|
|
51
|
+
clientInfo?: { name?: string; version?: string; [key: string]: unknown },
|
|
52
|
+
tools?: ClientToolDefinition[],
|
|
53
|
+
services?: { hasLLM: boolean; hasApproval: boolean; hasEmbedding: boolean; hasTools: boolean }
|
|
54
|
+
): Promise<{
|
|
55
|
+
clientId: string;
|
|
56
|
+
token: string;
|
|
57
|
+
expiresAt: number;
|
|
58
|
+
tokenRotateAt: number;
|
|
59
|
+
}> {
|
|
60
|
+
if (this.initPromise) {
|
|
61
|
+
await this.initPromise;
|
|
62
|
+
return {
|
|
63
|
+
clientId: this.clientId!,
|
|
64
|
+
token: this.clientToken!,
|
|
65
|
+
expiresAt: 0,
|
|
66
|
+
tokenRotateAt: 0,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
this.initPromise = (async () => {
|
|
71
|
+
await this.server.start();
|
|
72
|
+
|
|
73
|
+
const ctx = this.createContext({
|
|
74
|
+
method: 'POST',
|
|
75
|
+
path: '/api/init',
|
|
76
|
+
body: {
|
|
77
|
+
clientInfo,
|
|
78
|
+
tools: tools || [],
|
|
79
|
+
services,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const result = (await this.server.handleInit(ctx)) as {
|
|
84
|
+
clientId: string;
|
|
85
|
+
token: string;
|
|
86
|
+
expiresAt: number;
|
|
87
|
+
tokenRotateAt: number;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
this.clientId = result.clientId;
|
|
91
|
+
this.clientToken = result.token;
|
|
92
|
+
this.initialized = true;
|
|
93
|
+
})();
|
|
94
|
+
|
|
95
|
+
await this.initPromise;
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
clientId: this.clientId!,
|
|
99
|
+
token: this.clientToken!,
|
|
100
|
+
expiresAt: 0,
|
|
101
|
+
tokenRotateAt: 0,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
getClientId(): string {
|
|
106
|
+
if (!this.clientId) {
|
|
107
|
+
throw new Error('Client not initialized. Call init() first.');
|
|
108
|
+
}
|
|
109
|
+
return this.clientId;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async ensureInitialized(): Promise<void> {
|
|
113
|
+
if (!this.initialized) {
|
|
114
|
+
throw new Error('Client not initialized. Call init() first.');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
getHeaders(): Record<string, string> {
|
|
119
|
+
const headers: Record<string, string> = {
|
|
120
|
+
'content-type': 'application/json',
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
if (this.clientId) {
|
|
124
|
+
headers['x-client-id'] = this.clientId;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (this.clientToken) {
|
|
128
|
+
headers['authorization'] = `Bearer ${this.clientToken}`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return headers;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
getBaseUrl(): string {
|
|
135
|
+
return '';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
updateToken(_response: Response): void {
|
|
139
|
+
// No-op for in-process - tokens are managed directly
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async prepareHeaders(
|
|
143
|
+
_method: string,
|
|
144
|
+
_url: string,
|
|
145
|
+
_body?: unknown
|
|
146
|
+
): Promise<Record<string, string>> {
|
|
147
|
+
return this.getHeaders();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async getDefinitions(options?: { apiGroups?: string[] }): Promise<{
|
|
151
|
+
typescript: string;
|
|
152
|
+
version: string;
|
|
153
|
+
apiGroups: string[];
|
|
154
|
+
}> {
|
|
155
|
+
await this.ensureInitialized();
|
|
156
|
+
|
|
157
|
+
const ctx = this.createContext({
|
|
158
|
+
method: 'GET',
|
|
159
|
+
path: '/api/definitions',
|
|
160
|
+
query: options?.apiGroups ? { apiGroups: options.apiGroups.join(',') } : {},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
return (await this.server.getDefinitions(ctx)) as {
|
|
164
|
+
typescript: string;
|
|
165
|
+
version: string;
|
|
166
|
+
apiGroups: string[];
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async getRuntimeDefinitions(options?: { apis?: string[] }): Promise<string> {
|
|
171
|
+
await this.ensureInitialized();
|
|
172
|
+
|
|
173
|
+
const ctx = this.createContext({
|
|
174
|
+
method: 'GET',
|
|
175
|
+
path: '/api/runtime',
|
|
176
|
+
query: options?.apis?.length ? { apis: options.apis.join(',') } : {},
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return await this.server.getRuntimeDefinitions(ctx);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async getServerInfo(): Promise<{
|
|
183
|
+
version: string;
|
|
184
|
+
capabilities: Record<string, boolean>;
|
|
185
|
+
}> {
|
|
186
|
+
await this.ensureInitialized();
|
|
187
|
+
return this.server.getInfo() as {
|
|
188
|
+
version: string;
|
|
189
|
+
capabilities: Record<string, boolean>;
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async search(query: string, options?: Record<string, unknown>): Promise<{ results: unknown[] }> {
|
|
194
|
+
await this.ensureInitialized();
|
|
195
|
+
|
|
196
|
+
const ctx = this.createContext({
|
|
197
|
+
method: 'POST',
|
|
198
|
+
path: '/api/search',
|
|
199
|
+
body: { query, ...options },
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
return (await this.server.handleSearch(ctx)) as { results: unknown[] };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async explore(path: string): Promise<unknown> {
|
|
206
|
+
await this.ensureInitialized();
|
|
207
|
+
|
|
208
|
+
const ctx = this.createContext({
|
|
209
|
+
method: 'POST',
|
|
210
|
+
path: '/api/explore',
|
|
211
|
+
body: { path },
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return await this.server.handleExplore(ctx);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async execute(code: string, config?: Record<string, unknown>): Promise<unknown> {
|
|
218
|
+
await this.ensureInitialized();
|
|
219
|
+
|
|
220
|
+
const ctx = this.createContext({
|
|
221
|
+
method: 'POST',
|
|
222
|
+
path: '/api/execute',
|
|
223
|
+
body: { code, config },
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
return await this.server.handleExecute(ctx);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async resume(executionId: string, callbackResult: unknown): Promise<unknown> {
|
|
230
|
+
await this.ensureInitialized();
|
|
231
|
+
|
|
232
|
+
const ctx = this.createContext({
|
|
233
|
+
method: 'POST',
|
|
234
|
+
path: `/api/resume/${executionId}`,
|
|
235
|
+
body: { result: callbackResult },
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
return await this.server.handleResume(ctx, executionId);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async resumeWithBatchResults(
|
|
242
|
+
executionId: string,
|
|
243
|
+
batchResults: Array<{ id: string; result: unknown }>
|
|
244
|
+
): Promise<unknown> {
|
|
245
|
+
await this.ensureInitialized();
|
|
246
|
+
|
|
247
|
+
const ctx = this.createContext({
|
|
248
|
+
method: 'POST',
|
|
249
|
+
path: `/api/resume/${executionId}`,
|
|
250
|
+
body: { results: batchResults },
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
return await this.server.handleResume(ctx, executionId);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
private createContext(options: {
|
|
257
|
+
method: string;
|
|
258
|
+
path: string;
|
|
259
|
+
query?: Record<string, string>;
|
|
260
|
+
body?: unknown;
|
|
261
|
+
}): InProcessRequestContext {
|
|
262
|
+
const noopLogger = {
|
|
263
|
+
debug: () => {},
|
|
264
|
+
info: () => {},
|
|
265
|
+
warn: () => {},
|
|
266
|
+
error: () => {},
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
return {
|
|
270
|
+
method: options.method,
|
|
271
|
+
path: options.path,
|
|
272
|
+
query: options.query || {},
|
|
273
|
+
headers: this.getHeaders(),
|
|
274
|
+
body: options.body,
|
|
275
|
+
clientId: this.clientId,
|
|
276
|
+
clientToken: this.clientToken,
|
|
277
|
+
logger: noopLogger,
|
|
278
|
+
status: 200,
|
|
279
|
+
responseBody: null,
|
|
280
|
+
throw: (status: number, message: string) => {
|
|
281
|
+
const error = new Error(message);
|
|
282
|
+
(error as Error & { status: number }).status = status;
|
|
283
|
+
throw error;
|
|
284
|
+
},
|
|
285
|
+
assert: (condition: boolean, message: string) => {
|
|
286
|
+
if (!condition) {
|
|
287
|
+
throw new Error(message);
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
set: () => {},
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
package/src/core/index.ts
CHANGED
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
export interface TokenEntry {
|
|
8
8
|
token: string;
|
|
9
9
|
addedAt: number;
|
|
10
|
+
sequence: number;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export class ProvenanceTokenRegistry {
|
|
13
14
|
private cache: Map<string, TokenEntry> = new Map();
|
|
14
15
|
private maxSize: number;
|
|
15
16
|
private ttl: number;
|
|
17
|
+
private sequenceCounter: number = 0;
|
|
16
18
|
|
|
17
19
|
constructor(maxSize: number = 10000, ttlHours: number = 1) {
|
|
18
20
|
this.maxSize = maxSize;
|
|
@@ -31,17 +33,23 @@ export class ProvenanceTokenRegistry {
|
|
|
31
33
|
this.evictLRU();
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
// Store token
|
|
36
|
+
// Store token with sequence number for stable ordering
|
|
35
37
|
this.cache.set(token, {
|
|
36
38
|
token,
|
|
37
39
|
addedAt: Date.now(),
|
|
40
|
+
sequence: this.sequenceCounter++,
|
|
38
41
|
});
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
/**
|
|
42
45
|
* Get recent tokens (non-expired, sorted by age, limited)
|
|
46
|
+
* Returns tokens in chronological order (oldest first, most recent last)
|
|
43
47
|
*/
|
|
44
48
|
getRecentTokens(maxCount: number = 1000): string[] {
|
|
49
|
+
if (maxCount <= 0) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
|
|
45
53
|
this.evictExpired();
|
|
46
54
|
|
|
47
55
|
const now = Date.now();
|
|
@@ -66,8 +74,8 @@ export class ProvenanceTokenRegistry {
|
|
|
66
74
|
return false;
|
|
67
75
|
}
|
|
68
76
|
})
|
|
69
|
-
.sort((a, b) =>
|
|
70
|
-
.slice(
|
|
77
|
+
.sort((a, b) => a.sequence - b.sequence)
|
|
78
|
+
.slice(-maxCount);
|
|
71
79
|
|
|
72
80
|
for (const token of expiredTokens) {
|
|
73
81
|
this.cache.delete(token);
|
|
@@ -113,11 +121,11 @@ export class ProvenanceTokenRegistry {
|
|
|
113
121
|
*/
|
|
114
122
|
private evictLRU(): void {
|
|
115
123
|
let oldestToken: string | null = null;
|
|
116
|
-
let
|
|
124
|
+
let oldestSequence = Infinity;
|
|
117
125
|
|
|
118
126
|
for (const [token, entry] of this.cache.entries()) {
|
|
119
|
-
if (entry.
|
|
120
|
-
|
|
127
|
+
if (entry.sequence < oldestSequence) {
|
|
128
|
+
oldestSequence = entry.sequence;
|
|
121
129
|
oldestToken = token;
|
|
122
130
|
}
|
|
123
131
|
}
|
package/src/core/session.ts
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
import type { ClientHooks } from './types.js';
|
|
2
2
|
import type { ClientToolDefinition } from '@mondaydotcomorg/atp-protocol';
|
|
3
3
|
|
|
4
|
-
export
|
|
4
|
+
export interface ISession {
|
|
5
|
+
init(
|
|
6
|
+
clientInfo?: { name?: string; version?: string; [key: string]: unknown },
|
|
7
|
+
tools?: ClientToolDefinition[],
|
|
8
|
+
services?: { hasLLM: boolean; hasApproval: boolean; hasEmbedding: boolean; hasTools: boolean }
|
|
9
|
+
): Promise<{
|
|
10
|
+
clientId: string;
|
|
11
|
+
token: string;
|
|
12
|
+
expiresAt: number;
|
|
13
|
+
tokenRotateAt: number;
|
|
14
|
+
}>;
|
|
15
|
+
getClientId(): string;
|
|
16
|
+
ensureInitialized(): Promise<void>;
|
|
17
|
+
getHeaders(): Record<string, string>;
|
|
18
|
+
getBaseUrl(): string;
|
|
19
|
+
updateToken(response: Response): void;
|
|
20
|
+
prepareHeaders(method: string, url: string, body?: unknown): Promise<Record<string, string>>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class ClientSession implements ISession {
|
|
5
24
|
private baseUrl: string;
|
|
6
25
|
private customHeaders: Record<string, string>;
|
|
7
26
|
private clientId?: string;
|
package/src/index.ts
CHANGED
|
@@ -9,3 +9,5 @@ export type { RuntimeAPIName } from '@mondaydotcomorg/atp-runtime';
|
|
|
9
9
|
export type { Tool, ToolName } from './tools/types.js';
|
|
10
10
|
export { ToolNames } from './tools/types.js';
|
|
11
11
|
export type { AgentToolProtocolClientOptions } from './client.js';
|
|
12
|
+
export { InProcessSession } from './core/in-process-session.js';
|
|
13
|
+
export type { ISession } from './core/session.js';
|