@adminforth/agent 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.
Files changed (66) hide show
  1. package/.woodpecker/buildRelease.sh +13 -0
  2. package/.woodpecker/buildSlackNotify.sh +46 -0
  3. package/.woodpecker/release.yml +57 -0
  4. package/agent/middleware/apiBasedTools.ts +109 -0
  5. package/agent/middleware/sequenceDebug.ts +302 -0
  6. package/agent/simpleAgent.ts +291 -0
  7. package/agent/skills/registry.ts +135 -0
  8. package/agent/systemPrompt.ts +69 -0
  9. package/agent/toolCallEvents.ts +17 -0
  10. package/agent/tools/apiTool.ts +99 -0
  11. package/agent/tools/fetchSkill.ts +58 -0
  12. package/agent/tools/fetchToolSchema.ts +50 -0
  13. package/agent/tools/index.ts +26 -0
  14. package/apiBasedTools.ts +625 -0
  15. package/build.log +30 -0
  16. package/custom/ChatSurface.vue +184 -0
  17. package/custom/ConversationArea.vue +175 -0
  18. package/custom/Message.vue +206 -0
  19. package/custom/SessionsHistory.vue +93 -0
  20. package/custom/ToolRenderer.vue +131 -0
  21. package/custom/ToolsGroup.vue +67 -0
  22. package/custom/incremark_code_renderers/IncremarkShikiCodeBlock.vue +301 -0
  23. package/custom/incremark_code_renderers/incremarkCodeHighlight.ts +285 -0
  24. package/custom/incremark_code_renderers/incremarkRenderer.ts +653 -0
  25. package/custom/incremark_code_renderers/renderIncremarkMarkdown.ts +118 -0
  26. package/custom/package.json +26 -0
  27. package/custom/pnpm-lock.yaml +1467 -0
  28. package/custom/skills/fetch_data/SKILL.md +15 -0
  29. package/custom/skills/mutate_data/SKILL.md +108 -0
  30. package/custom/tsconfig.json +16 -0
  31. package/custom/types.ts +34 -0
  32. package/custom/useAgentStore.ts +349 -0
  33. package/dist/agent/middleware/apiBasedTools.js +91 -0
  34. package/dist/agent/middleware/sequenceDebug.js +210 -0
  35. package/dist/agent/simpleAgent.js +173 -0
  36. package/dist/agent/skills/registry.js +108 -0
  37. package/dist/agent/systemPrompt.js +64 -0
  38. package/dist/agent/toolCallEvents.js +1 -0
  39. package/dist/agent/tools/apiTool.js +93 -0
  40. package/dist/agent/tools/fetchSkill.js +51 -0
  41. package/dist/agent/tools/fetchToolSchema.js +36 -0
  42. package/dist/agent/tools/index.js +28 -0
  43. package/dist/apiBasedTools.js +412 -0
  44. package/dist/custom/ChatSurface.vue +184 -0
  45. package/dist/custom/ConversationArea.vue +175 -0
  46. package/dist/custom/Message.vue +206 -0
  47. package/dist/custom/SessionsHistory.vue +93 -0
  48. package/dist/custom/ToolRenderer.vue +131 -0
  49. package/dist/custom/ToolsGroup.vue +67 -0
  50. package/dist/custom/incremark_code_renderers/IncremarkShikiCodeBlock.vue +301 -0
  51. package/dist/custom/incremark_code_renderers/incremarkCodeHighlight.ts +285 -0
  52. package/dist/custom/incremark_code_renderers/incremarkRenderer.ts +653 -0
  53. package/dist/custom/incremark_code_renderers/renderIncremarkMarkdown.ts +118 -0
  54. package/dist/custom/package.json +26 -0
  55. package/dist/custom/pnpm-lock.yaml +1467 -0
  56. package/dist/custom/skills/fetch_data/SKILL.md +15 -0
  57. package/dist/custom/skills/mutate_data/SKILL.md +108 -0
  58. package/dist/custom/tsconfig.json +16 -0
  59. package/dist/custom/types.ts +34 -0
  60. package/dist/custom/useAgentStore.ts +349 -0
  61. package/dist/index.js +415 -0
  62. package/dist/types.js +1 -0
  63. package/index.ts +457 -0
  64. package/package.json +58 -0
  65. package/tsconfig.json +13 -0
  66. package/types.ts +45 -0
@@ -0,0 +1,131 @@
1
+ <template>
2
+ <div v-if="props.data?.toolInfo" class="inline-flex m-2 max-w-[80%] flex-col gap-3 rounded-xl p-2 text-lightListTableHeadingText dark:text-darkListTableHeadingText">
3
+ <div class="flex items-center gap-3">
4
+ <div class="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-white/70 dark:bg-blue-700/20">
5
+ <Spinner v-if="isRunning" class="h-4 w-4" />
6
+ <IconCheckOutline v-else class="h-4 w-4 text-lightPrimary dark:text-darkPrimary" />
7
+ </div>
8
+
9
+ <div class="min-w-0">
10
+ <p class="text-xs text-gray-500 dark:text-gray-400 font-bold">
11
+ {{ statusLabel }}
12
+ <span v-if="props.data?.toolInfo?.durationMs" class="text-xs">({{ (props.data.toolInfo.durationMs / 1000).toFixed(2) }}s)</span>
13
+ </p>
14
+ <p class="break-all font-mono text-sm leading-5">
15
+ {{ props.data?.toolInfo?.toolName }}
16
+ </p>
17
+ </div>
18
+ <IconAngleDownOutline
19
+ v-if="hasToolSections"
20
+ :class="isInputOutputExpanded ? 'rotate-180' : 'rotate-0'"
21
+ class="cursor-pointer transition-transform duration-200 hover:scale-105 hover:opacity-75"
22
+ @click="isInputOutputExpanded = !isInputOutputExpanded"
23
+ />
24
+ </div>
25
+ <transition name="expand">
26
+ <div v-show="isInputOutputExpanded" class="max-h-72 space-y-3 overflow-y-auto pr-1">
27
+ <section
28
+ v-for="section in toolSections"
29
+ :key="section.label"
30
+ class="overflow-hidden rounded-xl border border-black/5 bg-white/70 shadow-sm backdrop-blur-sm dark:border-white/10 dark:bg-slate-900/50"
31
+ >
32
+ <header class="border-b border-black/5 px-3 py-2 text-[11px] font-semibold uppercase tracking-[0.22em] text-gray-500 dark:border-white/10 dark:text-gray-400">
33
+ {{ section.label }}
34
+ </header>
35
+ <div class="grid grid-cols-[auto,1fr] gap-x-3 gap-y-1 px-3 py-3 font-mono text-xs leading-5 text-gray-700 dark:text-gray-200">
36
+ <template v-for="line in section.lines" :key="`${section.label}-${line.number}`">
37
+ <span class="select-none text-[11px] text-gray-400 dark:text-gray-500">{{ line.number }}</span>
38
+ <span class="whitespace-pre-wrap break-words">{{ line.content || ' ' }}</span>
39
+ </template>
40
+ </div>
41
+ </section>
42
+ </div>
43
+ </transition>
44
+ </div>
45
+ </template>
46
+
47
+ <script setup lang="ts">
48
+ import { computed, ref } from 'vue';
49
+ import { type IPartData } from './types';
50
+ import { Spinner } from '@/afcl';
51
+ import { IconAngleDownOutline, IconCheckOutline } from '@iconify-prerendered/vue-flowbite';
52
+
53
+ const isInputOutputExpanded = ref(false);
54
+
55
+ interface IToolSection {
56
+ label: string;
57
+ lines: Array<{
58
+ number: number;
59
+ content: string;
60
+ }>;
61
+ }
62
+
63
+ const props = defineProps<{
64
+ data: {
65
+ type: string;
66
+ toolInfo: IPartData;
67
+ }
68
+ }>();
69
+
70
+ const isRunning = computed(() => props.data?.toolInfo?.phase === 'start');
71
+ const statusLabel = computed(() => isRunning.value ? 'Running tool' : 'Tool finished');
72
+
73
+ const normalizeToolPayload = (value: unknown): string | null => {
74
+ if (value === null || value === undefined || value === '') {
75
+ return null;
76
+ }
77
+
78
+ if (typeof value === 'string') {
79
+ return value.trim();
80
+ }
81
+
82
+ return JSON.stringify(value, null, 2);
83
+ };
84
+
85
+ const toolSections = computed<IToolSection[]>(() => {
86
+ const sections = [
87
+ {
88
+ label: 'Input',
89
+ content: normalizeToolPayload(props.data.toolInfo.input),
90
+ },
91
+ {
92
+ label: 'Output',
93
+ content: normalizeToolPayload(props.data.toolInfo.output),
94
+ },
95
+ ];
96
+
97
+ return sections
98
+ .filter((section): section is { label: string; content: string } => Boolean(section.content))
99
+ .map(section => ({
100
+ label: section.label,
101
+ lines: section.content.split('\n').map((content, index) => ({
102
+ number: index + 1,
103
+ content,
104
+ })),
105
+ }));
106
+ });
107
+
108
+ const hasToolSections = computed(() => toolSections.value.length > 0);
109
+ </script>
110
+
111
+
112
+ <style scoped>
113
+
114
+ .expand-enter-active,
115
+ .expand-leave-active {
116
+ transition: all 0.3s ease;
117
+ }
118
+
119
+ .expand-enter-from,
120
+ .expand-leave-to {
121
+ opacity: 0;
122
+ max-height: 0;
123
+ }
124
+
125
+ .expand-enter-to,
126
+ .expand-leave-from {
127
+ opacity: 1;
128
+ max-height: 288px;
129
+ }
130
+
131
+ </style>
@@ -0,0 +1,67 @@
1
+ <template>
2
+ <template v-for="group in props.toolGroup" :key="group.title">
3
+ <div v-if="group.groupedTools.length > 1" class="mb-4 flex flex-col">
4
+ <div class="flex items-center gap-2 p-2 m-2 cursor-pointer hover:opacity-75 break-all font-mono text-sm leading-5" @click="toggleGroup(group.title)">
5
+ - {{ group.title }} {{ 'x' + group.groupedTools.length }}
6
+ <IconAngleDownOutline
7
+ class="transition-transform duration-200 hover:scale-105 hover:opacity-75"
8
+ :class="expandedGroups.includes(group.title) ? 'rotate-180' : 'rotate-0'"
9
+ />
10
+ </div>
11
+ <transition name="expand">
12
+ <div v-show="expandedGroups.includes(group.title)" class="flex flex-col">
13
+ <ToolRenderer v-for="part in group.groupedTools" :key="part.text + part.type" :data="part" />
14
+ </div>
15
+ </transition>
16
+ </div>
17
+ <ToolRenderer v-else :data="group.groupedTools[0]" />
18
+ </template>
19
+
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { Tool } from 'langchain';
24
+ import ToolRenderer from './ToolRenderer.vue';
25
+ import type { IPart } from './types';
26
+ import { ref } from 'vue';
27
+ import { IconAngleDownOutline } from '@iconify-prerendered/vue-flowbite';
28
+
29
+ const props = defineProps<{
30
+ toolGroup: {
31
+ title: string;
32
+ groupedTools: IPart[];
33
+ }[]
34
+ }>();
35
+
36
+ const expandedGroups = ref<string[]>([]);
37
+
38
+ function toggleGroup(groupTitle: string) {
39
+ if (expandedGroups.value.includes(groupTitle)) {
40
+ expandedGroups.value = expandedGroups.value.filter((title: string) => title !== groupTitle);
41
+ } else {
42
+ expandedGroups.value.push(groupTitle);
43
+ }
44
+ }
45
+
46
+ </script>
47
+
48
+ <style scoped>
49
+
50
+ .expand-enter-active,
51
+ .expand-leave-active {
52
+ transition: all 0.3s ease;
53
+ }
54
+
55
+ .expand-enter-from,
56
+ .expand-leave-to {
57
+ opacity: 0;
58
+ max-height: 0;
59
+ }
60
+
61
+ .expand-enter-to,
62
+ .expand-leave-from {
63
+ opacity: 1;
64
+ max-height: 288px;
65
+ }
66
+
67
+ </style>
@@ -0,0 +1,301 @@
1
+ <template>
2
+ <div
3
+ class="incremark-shiki-code"
4
+ :data-stream-state="props.blockStatus"
5
+ >
6
+ <div class="incremark-shiki-toolbar">
7
+ <span class="incremark-shiki-language">{{ languageLabel }}</span>
8
+ <button
9
+ type="button"
10
+ class="incremark-shiki-copy"
11
+ :class="copied ? 'is-copied' : ''"
12
+ :disabled="!sourceCode"
13
+ @click="copyCode"
14
+ >
15
+ {{ copied ? 'Copied' : 'Copy' }}
16
+ </button>
17
+ </div>
18
+
19
+ <div class="incremark-shiki-body">
20
+ <div
21
+ v-if="renderedHtml"
22
+ class="incremark-shiki-html"
23
+ v-html="renderedHtml"
24
+ />
25
+
26
+ <pre v-else class="incremark-shiki-fallback"><code>{{ sourceCode }}</code></pre>
27
+ </div>
28
+ </div>
29
+ </template>
30
+
31
+ <script setup lang="ts">
32
+ import type { Code } from 'mdast';
33
+ import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
34
+
35
+ import { highlightCodeSnippetHtml, type IncremarkCodeTheme } from './incremarkCodeHighlight';
36
+
37
+ const props = withDefaults(defineProps<{
38
+ node: Code;
39
+ lightTheme?: string;
40
+ darkTheme?: string;
41
+ theme?: string;
42
+ fallbackTheme?: string;
43
+ disableHighlight?: boolean;
44
+ blockStatus?: 'pending' | 'stable' | 'completed';
45
+ }>(), {
46
+ lightTheme: 'github-light',
47
+ darkTheme: 'github-dark',
48
+ fallbackTheme: 'github-dark',
49
+ disableHighlight: false,
50
+ blockStatus: 'completed',
51
+ });
52
+
53
+ const renderedHtml = ref('');
54
+ const copied = ref(false);
55
+ const prefersDarkMode = ref(isDarkDocument());
56
+
57
+ let copyResetTimeout: number | null = null;
58
+ let renderRequestId = 0;
59
+ let scheduledFrameId: number | null = null;
60
+ let themeObserver: MutationObserver | null = null;
61
+
62
+ const sourceCode = computed(() => props.node.value ?? '');
63
+ const language = computed(() => props.node.lang?.trim().toLowerCase() || 'text');
64
+ const languageLabel = computed(() => props.node.lang?.trim() || 'text');
65
+ const codeTheme = computed<IncremarkCodeTheme>(() => {
66
+ const requestedTheme = props.theme ?? (prefersDarkMode.value ? props.darkTheme : props.lightTheme);
67
+
68
+ if (requestedTheme === 'github-light') {
69
+ return 'light';
70
+ }
71
+
72
+ if (requestedTheme === 'github-dark') {
73
+ return 'dark';
74
+ }
75
+
76
+ return props.fallbackTheme === 'github-light' ? 'light' : 'dark';
77
+ });
78
+
79
+ watch(
80
+ [sourceCode, language, codeTheme, () => props.disableHighlight],
81
+ () => {
82
+ scheduleHighlight();
83
+ },
84
+ { immediate: true }
85
+ );
86
+
87
+ onMounted(() => {
88
+ if (typeof MutationObserver === 'undefined' || typeof document === 'undefined') {
89
+ return;
90
+ }
91
+
92
+ themeObserver = new MutationObserver(() => {
93
+ prefersDarkMode.value = isDarkDocument();
94
+ });
95
+
96
+ themeObserver.observe(document.documentElement, {
97
+ attributes: true,
98
+ attributeFilter: ['class'],
99
+ });
100
+ });
101
+
102
+ onBeforeUnmount(() => {
103
+ renderRequestId += 1;
104
+
105
+ if (copyResetTimeout !== null) {
106
+ window.clearTimeout(copyResetTimeout);
107
+ }
108
+
109
+ if (scheduledFrameId !== null) {
110
+ window.cancelAnimationFrame(scheduledFrameId);
111
+ }
112
+
113
+ themeObserver?.disconnect();
114
+ });
115
+
116
+ async function copyCode() {
117
+ if (!sourceCode.value || typeof navigator === 'undefined' || !navigator.clipboard) {
118
+ return;
119
+ }
120
+
121
+ try {
122
+ await navigator.clipboard.writeText(sourceCode.value);
123
+ copied.value = true;
124
+
125
+ if (copyResetTimeout !== null) {
126
+ window.clearTimeout(copyResetTimeout);
127
+ }
128
+
129
+ copyResetTimeout = window.setTimeout(() => {
130
+ copied.value = false;
131
+ copyResetTimeout = null;
132
+ }, 1500);
133
+ } catch (error) {
134
+ console.error('Failed to copy code block', error);
135
+ }
136
+ }
137
+
138
+ function scheduleHighlight() {
139
+ if (typeof window === 'undefined') {
140
+ void renderHighlight();
141
+ return;
142
+ }
143
+
144
+ if (scheduledFrameId !== null) {
145
+ window.cancelAnimationFrame(scheduledFrameId);
146
+ }
147
+
148
+ scheduledFrameId = window.requestAnimationFrame(() => {
149
+ scheduledFrameId = null;
150
+ void renderHighlight();
151
+ });
152
+ }
153
+
154
+ async function renderHighlight() {
155
+ const requestId = ++renderRequestId;
156
+
157
+ if (!sourceCode.value || props.disableHighlight) {
158
+ renderedHtml.value = '';
159
+ return;
160
+ }
161
+
162
+ try {
163
+ const html = await highlightCodeSnippetHtml(sourceCode.value, language.value, codeTheme.value);
164
+
165
+ if (requestId === renderRequestId) {
166
+ renderedHtml.value = html;
167
+ }
168
+ } catch (error) {
169
+ if (requestId === renderRequestId) {
170
+ renderedHtml.value = '';
171
+ }
172
+
173
+ console.error('Failed to highlight streamed code block', error);
174
+ }
175
+ }
176
+
177
+ function isDarkDocument(): boolean {
178
+ return typeof document !== 'undefined' && document.documentElement.classList.contains('dark');
179
+ }
180
+ </script>
181
+
182
+ <style scoped>
183
+ .incremark-shiki-code {
184
+ --incremark-code-border: rgba(148, 163, 184, 0.24);
185
+ --incremark-code-toolbar-bg: rgba(248, 250, 252, 0.9);
186
+ --incremark-code-toolbar-text: #475569;
187
+ --incremark-code-copy-bg: rgba(226, 232, 240, 0.9);
188
+ --incremark-code-copy-text: #0f172a;
189
+ border: 1px solid var(--incremark-code-border);
190
+ border-radius: 16px;
191
+ overflow: hidden;
192
+ width: 100%;
193
+ background:
194
+ linear-gradient(180deg, rgba(255, 255, 255, 0.94), rgba(248, 250, 252, 0.96));
195
+ box-shadow: 0 14px 30px -24px rgba(15, 23, 42, 0.45);
196
+ }
197
+
198
+ .dark .incremark-shiki-code {
199
+ --incremark-code-border: rgba(100, 116, 139, 0.38);
200
+ --incremark-code-toolbar-bg: rgba(15, 23, 42, 0.88);
201
+ --incremark-code-toolbar-text: #cbd5e1;
202
+ --incremark-code-copy-bg: rgba(30, 41, 59, 0.88);
203
+ --incremark-code-copy-text: #e2e8f0;
204
+ background:
205
+ linear-gradient(180deg, rgba(2, 6, 23, 0.96), rgba(15, 23, 42, 0.98));
206
+ }
207
+
208
+ .incremark-shiki-code[data-stream-state='pending'],
209
+ .incremark-shiki-code[data-stream-state='stable'] {
210
+ box-shadow: 0 10px 24px -24px rgba(15, 23, 42, 0.8);
211
+ }
212
+
213
+ .incremark-shiki-toolbar {
214
+ display: flex;
215
+ align-items: center;
216
+ justify-content: space-between;
217
+ gap: 12px;
218
+ padding: 10px 14px;
219
+ border-bottom: 1px solid var(--incremark-code-border);
220
+ background: var(--incremark-code-toolbar-bg);
221
+ backdrop-filter: blur(10px);
222
+ }
223
+
224
+ .incremark-shiki-language {
225
+ font-size: 11px;
226
+ font-weight: 600;
227
+ letter-spacing: 0.12em;
228
+ text-transform: uppercase;
229
+ color: var(--incremark-code-toolbar-text);
230
+ }
231
+
232
+ .incremark-shiki-copy {
233
+ border: none;
234
+ border-radius: 999px;
235
+ padding: 6px 10px;
236
+ font-size: 11px;
237
+ font-weight: 600;
238
+ letter-spacing: 0.04em;
239
+ background: var(--incremark-code-copy-bg);
240
+ color: var(--incremark-code-copy-text);
241
+ cursor: pointer;
242
+ transition: transform 0.16s ease, opacity 0.16s ease, background-color 0.16s ease;
243
+ }
244
+
245
+ .incremark-shiki-copy:hover:not(:disabled) {
246
+ transform: translateY(-1px);
247
+ }
248
+
249
+ .incremark-shiki-copy:disabled {
250
+ cursor: default;
251
+ opacity: 0.5;
252
+ }
253
+
254
+ .incremark-shiki-copy.is-copied {
255
+ background: rgba(16, 185, 129, 0.16);
256
+ color: #059669;
257
+ }
258
+
259
+ .dark .incremark-shiki-copy.is-copied {
260
+ background: rgba(16, 185, 129, 0.24);
261
+ color: #6ee7b7;
262
+ }
263
+
264
+ .incremark-shiki-body {
265
+ overflow-x: auto;
266
+ }
267
+
268
+ .incremark-shiki-fallback {
269
+ margin: 0;
270
+ padding: 18px;
271
+ overflow-x: auto;
272
+ background: transparent;
273
+ color: inherit;
274
+ }
275
+
276
+ .incremark-shiki-fallback code {
277
+ display: block;
278
+ font-family: 'JetBrains Mono', 'Fira Code', 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
279
+ font-size: 13px;
280
+ line-height: 1.65;
281
+ white-space: pre;
282
+ }
283
+
284
+ :deep(.incremark-shiki-html pre.shiki) {
285
+ margin: 0;
286
+ padding: 18px;
287
+ overflow-x: auto;
288
+ background: transparent !important;
289
+ font-size: 13px;
290
+ line-height: 1.65;
291
+ }
292
+
293
+ :deep(.incremark-shiki-html code) {
294
+ display: block;
295
+ font-family: 'JetBrains Mono', 'Fira Code', 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
296
+ }
297
+
298
+ :deep(.incremark-shiki-html .line) {
299
+ min-height: 1.65em;
300
+ }
301
+ </style>