@frost1994/agentic-core 1.0.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/dist/index.js ADDED
@@ -0,0 +1,606 @@
1
+ import { g as generateId } from "./index-CesPelb5.js";
2
+ import { E, S, a, c, b, d, e, f, h, i, j, k, l, m, n, o, p, t } from "./index-CesPelb5.js";
3
+ class AiHttpError extends Error {
4
+ constructor(code, message, traceId) {
5
+ super(message);
6
+ this.name = "AiHttpError";
7
+ this.code = code;
8
+ this.traceId = traceId;
9
+ }
10
+ }
11
+ class AiHttpClient {
12
+ constructor(baseUrl, headersProvider) {
13
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
14
+ this.headersProvider = headersProvider;
15
+ }
16
+ async getPluginConfig(systemCode) {
17
+ const raw = await this.request(
18
+ "GET",
19
+ `/plugin/config?systemCode=${encodeURIComponent(systemCode)}`
20
+ ).catch(() => null);
21
+ if (!raw) {
22
+ return null;
23
+ }
24
+ return {
25
+ systemCode: raw.systemCode ?? systemCode,
26
+ defaultMode: raw.defaultMode ?? "floating",
27
+ themeStrategy: raw.themeStrategy ?? "system",
28
+ themePreset: raw.themePreset ?? "light",
29
+ primaryColor: raw.primaryColor ?? "#409EFF",
30
+ defaultModelCode: raw.defaultModelCode ?? "default",
31
+ enableFullscreen: Boolean(raw.enableFullscreen ?? true),
32
+ enableDrawer: Boolean(raw.enableDrawer ?? true),
33
+ enableKnowledge: Boolean(raw.enableKnowledge ?? false),
34
+ enableText2Sql: Boolean(raw.enableText2Sql ?? true),
35
+ rateLimitPerHour: Number(raw.rateLimitPerHour ?? 100)
36
+ };
37
+ }
38
+ async listModels() {
39
+ const raw = await this.request("GET", "/models");
40
+ return raw.map((item) => ({
41
+ code: item.code ?? item.modelCode ?? "",
42
+ name: item.name ?? item.modelName ?? "",
43
+ supportStream: Boolean(item.supportStream ?? true),
44
+ supportToolCall: Boolean(item.supportToolCall ?? false),
45
+ bestFor: (item.bestFor ?? []).filter(Boolean),
46
+ maxTokens: typeof item.maxTokens === "number" ? item.maxTokens : void 0
47
+ })).filter((item) => item.code && item.name);
48
+ }
49
+ async createConversation(systemCode, title, modelCode) {
50
+ return this.request("POST", "/conversations", {
51
+ systemCode,
52
+ title: title ?? "New conversation",
53
+ modelCode: modelCode ?? "default"
54
+ });
55
+ }
56
+ async listConversations(systemCode, page = 1, size = 20) {
57
+ return this.request(
58
+ "GET",
59
+ `/conversations?systemCode=${encodeURIComponent(systemCode)}&page=${page}&size=${size}`
60
+ );
61
+ }
62
+ async getMessages(conversationId) {
63
+ return this.request(
64
+ "GET",
65
+ `/conversations/${encodeURIComponent(conversationId)}/messages`
66
+ );
67
+ }
68
+ async deleteConversation(conversationId) {
69
+ await this.request(
70
+ "DELETE",
71
+ `/conversations/${encodeURIComponent(conversationId)}`
72
+ );
73
+ }
74
+ async getSuggestions(systemCode, sceneCode) {
75
+ let path = `/suggestions?systemCode=${encodeURIComponent(systemCode)}`;
76
+ if (sceneCode) {
77
+ path += `&sceneCode=${encodeURIComponent(sceneCode)}`;
78
+ }
79
+ return this.request("GET", path);
80
+ }
81
+ async confirmAction(actionId, confirm) {
82
+ await this.request("POST", "/actions/confirm", {
83
+ actionId,
84
+ confirm
85
+ });
86
+ }
87
+ async listDataSources() {
88
+ const raw = await this.request("GET", "/data-sources");
89
+ return raw.map((item) => ({
90
+ code: item.code ?? item.sourceCode ?? "",
91
+ name: item.name ?? item.sourceName ?? "",
92
+ type: item.type ?? item.dbType ?? "",
93
+ description: item.description
94
+ })).filter((item) => item.code && item.name);
95
+ }
96
+ async listTables(dataSourceCode) {
97
+ const raw = await this.request(
98
+ "GET",
99
+ `/data-sources/${encodeURIComponent(dataSourceCode)}/tables`
100
+ );
101
+ return raw.map((item) => ({
102
+ tableName: item.tableName ?? "",
103
+ tableComment: item.tableComment ?? item.tableAlias ?? item.description ?? void 0,
104
+ columns: Array.isArray(item.columns) ? item.columns : void 0
105
+ })).filter((item) => item.tableName);
106
+ }
107
+ async submitFeedback(messageId, rating, comment) {
108
+ await this.request("POST", "/feedback", {
109
+ messageId,
110
+ rating,
111
+ comment
112
+ });
113
+ }
114
+ async health() {
115
+ const healthUrl = this.baseUrl.endsWith("/api/ai") ? `${this.baseUrl.slice(0, -"/api/ai".length)}/actuator/health` : `${this.baseUrl}/health`;
116
+ const res = await fetch(healthUrl, {
117
+ method: "GET",
118
+ headers: this.headersProvider()
119
+ });
120
+ if (!res.ok) {
121
+ throw new AiHttpError(res.status, `HTTP ${res.status}: ${res.statusText}`);
122
+ }
123
+ const json = await res.json();
124
+ if ("code" in json) {
125
+ if (json.code !== 200) {
126
+ throw new AiHttpError(json.code, json.message ?? "Unknown API error", json.traceId);
127
+ }
128
+ return json.data;
129
+ }
130
+ return {
131
+ status: json.status,
132
+ service: "ai-gateway"
133
+ };
134
+ }
135
+ async request(method, path, body) {
136
+ const url = `${this.baseUrl}${path}`;
137
+ const headers = {
138
+ "Content-Type": "application/json",
139
+ ...this.headersProvider()
140
+ };
141
+ const init = {
142
+ method,
143
+ headers
144
+ };
145
+ if (body !== void 0 && (method === "POST" || method === "PUT" || method === "PATCH")) {
146
+ init.body = JSON.stringify(body);
147
+ }
148
+ const res = await fetch(url, init);
149
+ if (!res.ok) {
150
+ throw new AiHttpError(res.status, `HTTP ${res.status}: ${res.statusText}`);
151
+ }
152
+ if (res.status === 204 || method === "DELETE") {
153
+ return void 0;
154
+ }
155
+ const json = await res.json();
156
+ if (json.code !== void 0 && json.code !== 200) {
157
+ throw new AiHttpError(
158
+ json.code,
159
+ json.message ?? "Unknown API error",
160
+ json.traceId
161
+ );
162
+ }
163
+ return json.data;
164
+ }
165
+ }
166
+ function createInitialState(overrides) {
167
+ return {
168
+ visible: false,
169
+ mode: "floating",
170
+ previousMode: null,
171
+ position: { x: 0, y: 0 },
172
+ size: { width: 420, height: 600 },
173
+ systemCode: "",
174
+ modelCode: "",
175
+ currentConversationId: null,
176
+ conversations: [],
177
+ messagesByConversation: {},
178
+ toolStepsByMessage: {},
179
+ streamStatus: "idle",
180
+ lastSeq: 0,
181
+ lastHeartbeatAt: 0,
182
+ reconnectAttempt: 0,
183
+ themeMode: "system",
184
+ primaryColor: "#1677ff",
185
+ hasError: false,
186
+ lastError: null,
187
+ ...overrides
188
+ };
189
+ }
190
+ function reducer(state, action) {
191
+ switch (action.type) {
192
+ case "OPEN":
193
+ return {
194
+ ...state,
195
+ visible: true,
196
+ mode: action.mode ?? state.mode
197
+ };
198
+ case "CLOSE":
199
+ return { ...state, visible: false };
200
+ case "TOGGLE":
201
+ return { ...state, visible: !state.visible };
202
+ case "SWITCH_MODE": {
203
+ return {
204
+ ...state,
205
+ previousMode: state.mode,
206
+ mode: action.mode
207
+ };
208
+ }
209
+ case "SET_POSITION":
210
+ return {
211
+ ...state,
212
+ position: { x: action.x, y: action.y }
213
+ };
214
+ case "SET_SIZE":
215
+ return {
216
+ ...state,
217
+ size: { width: action.width, height: action.height }
218
+ };
219
+ case "SET_SYSTEM_CODE":
220
+ return { ...state, systemCode: action.systemCode };
221
+ case "SET_MODEL_CODE":
222
+ return { ...state, modelCode: action.modelCode };
223
+ case "SET_CONVERSATION":
224
+ return { ...state, currentConversationId: action.id };
225
+ case "ADD_CONVERSATION": {
226
+ const next = [action.conversation, ...state.conversations];
227
+ return { ...state, conversations: next };
228
+ }
229
+ case "SET_CONVERSATIONS":
230
+ return { ...state, conversations: action.conversations };
231
+ case "APPEND_MESSAGE": {
232
+ const list = state.messagesByConversation[action.conversationId] ?? [];
233
+ return {
234
+ ...state,
235
+ messagesByConversation: {
236
+ ...state.messagesByConversation,
237
+ [action.conversationId]: [...list, action.message]
238
+ }
239
+ };
240
+ }
241
+ case "APPEND_DELTA": {
242
+ const list = state.messagesByConversation[action.conversationId];
243
+ if (!list) return state;
244
+ const idx = list.findIndex((m2) => m2.id === action.messageId);
245
+ if (idx === -1) return state;
246
+ const next = list.slice();
247
+ next[idx] = { ...next[idx], content: next[idx].content + action.delta };
248
+ return {
249
+ ...state,
250
+ messagesByConversation: {
251
+ ...state.messagesByConversation,
252
+ [action.conversationId]: next
253
+ }
254
+ };
255
+ }
256
+ case "UPDATE_MESSAGE_STATUS": {
257
+ const list = state.messagesByConversation[action.conversationId];
258
+ if (!list) return state;
259
+ const idx = list.findIndex((m2) => m2.id === action.messageId);
260
+ if (idx === -1) return state;
261
+ const next = list.slice();
262
+ const msg = next[idx];
263
+ next[idx] = {
264
+ ...msg,
265
+ status: action.status,
266
+ finishedAt: action.status === "success" || action.status === "failed" ? (/* @__PURE__ */ new Date()).toISOString() : msg.finishedAt
267
+ };
268
+ return {
269
+ ...state,
270
+ messagesByConversation: {
271
+ ...state.messagesByConversation,
272
+ [action.conversationId]: next
273
+ }
274
+ };
275
+ }
276
+ case "SET_MESSAGES":
277
+ return {
278
+ ...state,
279
+ messagesByConversation: {
280
+ ...state.messagesByConversation,
281
+ [action.conversationId]: action.messages
282
+ }
283
+ };
284
+ case "APPEND_TOOL_STEP": {
285
+ const steps = state.toolStepsByMessage[action.messageId] ?? [];
286
+ return {
287
+ ...state,
288
+ toolStepsByMessage: {
289
+ ...state.toolStepsByMessage,
290
+ [action.messageId]: [...steps, action.step]
291
+ }
292
+ };
293
+ }
294
+ case "UPDATE_TOOL_STEP": {
295
+ const steps = state.toolStepsByMessage[action.messageId];
296
+ if (!steps) return state;
297
+ const idx = steps.findIndex((s) => s.stepId === action.stepId);
298
+ if (idx === -1) return state;
299
+ const next = steps.slice();
300
+ next[idx] = { ...next[idx], ...action.patch };
301
+ return {
302
+ ...state,
303
+ toolStepsByMessage: {
304
+ ...state.toolStepsByMessage,
305
+ [action.messageId]: next
306
+ }
307
+ };
308
+ }
309
+ case "SET_STREAM_STATUS":
310
+ return { ...state, streamStatus: action.status };
311
+ case "SET_LAST_SEQ":
312
+ return { ...state, lastSeq: action.seq };
313
+ case "SET_HEARTBEAT":
314
+ return { ...state, lastHeartbeatAt: action.ts };
315
+ case "INCREMENT_RECONNECT":
316
+ return { ...state, reconnectAttempt: state.reconnectAttempt + 1 };
317
+ case "RESET_RECONNECT":
318
+ return { ...state, reconnectAttempt: 0 };
319
+ case "SET_THEME":
320
+ return { ...state, themeMode: action.mode };
321
+ case "SET_PRIMARY_COLOR":
322
+ return { ...state, primaryColor: action.color };
323
+ case "SET_ERROR":
324
+ return {
325
+ ...state,
326
+ hasError: action.error !== null,
327
+ lastError: action.error
328
+ };
329
+ case "HYDRATE":
330
+ return { ...state, ...action.state };
331
+ default:
332
+ return state;
333
+ }
334
+ }
335
+ const SERIAL_VERSION = 1;
336
+ function serialize(state) {
337
+ const {
338
+ streamStatus,
339
+ lastSeq,
340
+ lastHeartbeatAt,
341
+ reconnectAttempt,
342
+ hasError,
343
+ lastError,
344
+ ...persistable
345
+ } = state;
346
+ return { version: SERIAL_VERSION, state: persistable };
347
+ }
348
+ function deserialize(data) {
349
+ if (!data || typeof data !== "object") return null;
350
+ const parsed = data;
351
+ if (parsed.version !== SERIAL_VERSION) return null;
352
+ return createInitialState(parsed.state);
353
+ }
354
+ function serializeToString(state) {
355
+ return JSON.stringify(serialize(state));
356
+ }
357
+ function deserializeFromString(json) {
358
+ try {
359
+ return deserialize(JSON.parse(json));
360
+ } catch {
361
+ return null;
362
+ }
363
+ }
364
+ class ToolRegistry {
365
+ constructor() {
366
+ this.tools = /* @__PURE__ */ new Map();
367
+ }
368
+ /** Register a tool with its definition and executor. */
369
+ register(definition, executor) {
370
+ this.tools.set(definition.name, { definition, executor });
371
+ }
372
+ /** Unregister a tool by name. */
373
+ unregister(name) {
374
+ return this.tools.delete(name);
375
+ }
376
+ /** Look up a registered tool. */
377
+ get(name) {
378
+ return this.tools.get(name);
379
+ }
380
+ /** Check whether a tool is registered. */
381
+ has(name) {
382
+ return this.tools.has(name);
383
+ }
384
+ /** List all registered tool names. */
385
+ list() {
386
+ return Array.from(this.tools.keys());
387
+ }
388
+ /** Get all definitions (for sending to LLM). */
389
+ getDefinitions() {
390
+ return Array.from(this.tools.values()).map((t2) => t2.definition);
391
+ }
392
+ /** Clear all registrations. */
393
+ clear() {
394
+ this.tools.clear();
395
+ }
396
+ }
397
+ class ToolOrchestrator {
398
+ constructor(options) {
399
+ this.registry = options.registry;
400
+ this.onStepStart = options.onStepStart;
401
+ this.onStepComplete = options.onStepComplete;
402
+ this.onStepError = options.onStepError;
403
+ }
404
+ /**
405
+ * Execute a plan of tool steps.
406
+ *
407
+ * - `serial`: steps run one after another; if one fails, abort the rest.
408
+ * - `parallel`: steps run concurrently; all results collected regardless of individual failures.
409
+ */
410
+ async execute(plan) {
411
+ if (plan.mode === "serial") {
412
+ return this.executeSerial(plan.steps);
413
+ }
414
+ return this.executeParallel(plan.steps);
415
+ }
416
+ /** Execute a single tool step. */
417
+ async executeSingle(toolName, args, title) {
418
+ var _a, _b, _c, _d;
419
+ const registered = this.registry.get(toolName);
420
+ if (!registered) {
421
+ const step2 = {
422
+ stepId: generateId("step_"),
423
+ toolName,
424
+ title: title ?? toolName,
425
+ status: "error",
426
+ args,
427
+ message: `Tool "${toolName}" is not registered`
428
+ };
429
+ (_a = this.onStepError) == null ? void 0 : _a.call(this, step2, new Error(step2.message));
430
+ return step2;
431
+ }
432
+ const step = {
433
+ stepId: generateId("step_"),
434
+ toolName,
435
+ title: title ?? registered.definition.description ?? toolName,
436
+ status: "running",
437
+ args
438
+ };
439
+ (_b = this.onStepStart) == null ? void 0 : _b.call(this, step);
440
+ const startTime = Date.now();
441
+ try {
442
+ const result = await registered.executor(args);
443
+ step.status = "success";
444
+ step.result = result;
445
+ step.durationMs = Date.now() - startTime;
446
+ (_c = this.onStepComplete) == null ? void 0 : _c.call(this, step);
447
+ return step;
448
+ } catch (err) {
449
+ step.status = "error";
450
+ step.result = err instanceof Error ? err.message : String(err);
451
+ step.durationMs = Date.now() - startTime;
452
+ (_d = this.onStepError) == null ? void 0 : _d.call(this, step, err instanceof Error ? err : new Error(String(err)));
453
+ return step;
454
+ }
455
+ }
456
+ async executeSerial(steps) {
457
+ const results = [];
458
+ for (const s of steps) {
459
+ const result = await this.executeSingle(s.toolName, s.args, s.title);
460
+ results.push(result);
461
+ if (result.status === "error") {
462
+ break;
463
+ }
464
+ }
465
+ return results;
466
+ }
467
+ async executeParallel(steps) {
468
+ return Promise.all(
469
+ steps.map((s) => this.executeSingle(s.toolName, s.args, s.title))
470
+ );
471
+ }
472
+ }
473
+ const _CitationParser = class _CitationParser {
474
+ /**
475
+ * Extract all citation markers from a text block.
476
+ *
477
+ * @param text — source text containing [1], [2], … markers
478
+ * @returns ordered list of citations with positions
479
+ */
480
+ parse(text) {
481
+ const citations = [];
482
+ let match;
483
+ _CitationParser.MARKER_RE.lastIndex = 0;
484
+ while ((match = _CitationParser.MARKER_RE.exec(text)) !== null) {
485
+ citations.push({
486
+ marker: match[0],
487
+ index: parseInt(match[1], 10),
488
+ start: match.index,
489
+ end: match.index + match[0].length
490
+ });
491
+ }
492
+ return citations;
493
+ }
494
+ /**
495
+ * Strip citation markers from text, returning clean text and a mapping.
496
+ *
497
+ * @returns `{ text: string, citations: Citation[] }`
498
+ */
499
+ strip(text) {
500
+ const citations = this.parse(text);
501
+ if (citations.length === 0) {
502
+ return { text, citations: [] };
503
+ }
504
+ let cleaned = "";
505
+ let lastEnd = 0;
506
+ for (const c2 of citations) {
507
+ cleaned += text.slice(lastEnd, c2.start);
508
+ lastEnd = c2.end;
509
+ }
510
+ cleaned += text.slice(lastEnd);
511
+ return { text: cleaned.trim(), citations };
512
+ }
513
+ /**
514
+ * Replace citation markers with custom formatter output.
515
+ *
516
+ * @param text — source text
517
+ * @param format — callback receiving citation index, returns replacement string
518
+ */
519
+ replace(text, format) {
520
+ return text.replace(_CitationParser.MARKER_RE, (_match, num) => format(parseInt(num, 10)));
521
+ }
522
+ };
523
+ _CitationParser.MARKER_RE = /\[(\d+)\]/g;
524
+ let CitationParser = _CitationParser;
525
+ class ChunkMatcher {
526
+ /**
527
+ * Match parsed citations to a list of knowledge chunks.
528
+ *
529
+ * @param citations — output from `CitationParser.parse()`
530
+ * @param chunks — chunks returned by backend (should be 1-based indexed)
531
+ * @returns chunks that were cited, with `citedBy` populated
532
+ */
533
+ match(citations, chunks) {
534
+ const citedIndices = new Set(citations.map((c2) => c2.index));
535
+ const indexToCitations = /* @__PURE__ */ new Map();
536
+ for (const c2 of citations) {
537
+ const arr = indexToCitations.get(c2.index) ?? [];
538
+ arr.push(c2.index);
539
+ indexToCitations.set(c2.index, arr);
540
+ }
541
+ const matched = [];
542
+ for (const chunk of chunks) {
543
+ if (citedIndices.has(chunk.index)) {
544
+ matched.push({
545
+ ...chunk,
546
+ citedBy: indexToCitations.get(chunk.index) ?? [chunk.index]
547
+ });
548
+ }
549
+ }
550
+ matched.sort((a2, b2) => a2.index - b2.index);
551
+ return matched;
552
+ }
553
+ /**
554
+ * Build a flat map: citation index → chunk.
555
+ *
556
+ * @returns Map where key is citation number and value is the matching chunk
557
+ */
558
+ buildIndexMap(chunks) {
559
+ const map = /* @__PURE__ */ new Map();
560
+ for (const chunk of chunks) {
561
+ map.set(chunk.index, chunk);
562
+ }
563
+ return map;
564
+ }
565
+ /**
566
+ * Find chunks that are NOT cited in the text (orphans).
567
+ */
568
+ findOrphans(citations, chunks) {
569
+ const cited = new Set(citations.map((c2) => c2.index));
570
+ return chunks.filter((c2) => !cited.has(c2.index));
571
+ }
572
+ }
573
+ export {
574
+ AiHttpClient,
575
+ AiHttpError,
576
+ ChunkMatcher,
577
+ CitationParser,
578
+ E as ErrorCodes,
579
+ S as SqlGuard,
580
+ a as SseClient,
581
+ ToolOrchestrator,
582
+ ToolRegistry,
583
+ c as clamp,
584
+ b as createError,
585
+ createInitialState,
586
+ d as debounce,
587
+ e as deepClone,
588
+ f as delay,
589
+ deserialize,
590
+ deserializeFromString,
591
+ h as formatDate,
592
+ i as formatDuration,
593
+ generateId,
594
+ j as isAborted,
595
+ k as isArray,
596
+ l as isFunction,
597
+ m as isNumber,
598
+ n as isObject,
599
+ o as isRetriable,
600
+ p as isString,
601
+ reducer,
602
+ serialize,
603
+ serializeToString,
604
+ t as throttle
605
+ };
606
+ //# sourceMappingURL=index.js.map