@kafca/agentdock 0.1.23 → 0.1.25
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 +3 -0
- package/dist/renderer/assets/{Badge-C2K5apfV.js → Badge-Bn2h-Qkf.js} +1 -1
- package/dist/renderer/assets/{Chat-DI2YeVKb.js → Chat-Cgo9aneg.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-DMAr15Oi.js → ChatMarkdown-CYzHfSiR.js} +1 -1
- package/dist/renderer/assets/{Config-7rP3EuUf.js → Config-DljB2-eP.js} +1 -1
- package/dist/renderer/assets/{CronList-81QslYE8.js → CronList-DeVbiY9a.js} +1 -1
- package/dist/renderer/assets/{Dashboard-Db2T7rSZ.js → Dashboard-fSqx5sm8.js} +2 -2
- package/dist/renderer/assets/{EmptyState-BBJ3cTvB.js → EmptyState-DgqKDwlq.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-Dz_6flG3.js → KnowledgeDetail-u8s2SmPV.js} +1 -1
- package/dist/renderer/assets/{KnowledgeHome-DIh046mN.js → KnowledgeHome-BdQw8nbY.js} +1 -1
- package/dist/renderer/assets/{Logs-BXBtHJLf.js → Logs-DSbndMpy.js} +1 -1
- package/dist/renderer/assets/{Modal-BB2Av_Xs.js → Modal-0d0EmAuK.js} +1 -1
- package/dist/renderer/assets/{Page-DPSdvMgU.js → Page-CVbOH_Kh.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-C6EWGvGg.js → ProjectDetail-C91tF7uA.js} +1 -1
- package/dist/renderer/assets/{ProjectList-BBo5ygnS.js → ProjectList-D78Pc-BQ.js} +1 -1
- package/dist/renderer/assets/{Select-CNX-Tx_O.js → Select-BbKzAIuO.js} +1 -1
- package/dist/renderer/assets/{SessionChat-BIn46jqZ.js → SessionChat-BERvL5e4.js} +1 -1
- package/dist/renderer/assets/{SessionList-CZt6f1Rd.js → SessionList-Bomz335M.js} +1 -1
- package/dist/renderer/assets/ThreadChat-CLr3amU2.js +23 -0
- package/dist/renderer/assets/{Workspace-C_4tdpjX.js → Workspace-In91z4W2.js} +1 -1
- package/dist/renderer/assets/{arrow-left-cHr5wkpq.js → arrow-left-FBnVKKBl.js} +1 -1
- package/dist/renderer/assets/{book-open-4nx5C8T-.js → book-open-4_CuP6Sa.js} +1 -1
- package/dist/renderer/assets/{check-exTS-R-x.js → check-vsoVjvac.js} +1 -1
- package/dist/renderer/assets/{chevron-down-DSvxXQa0.js → chevron-down-DFpmFTJW.js} +1 -1
- package/dist/renderer/assets/{circle-DyvEovdw.js → circle-vRULegER.js} +1 -1
- package/dist/renderer/assets/desktop-BkMW-h5p.js +4 -0
- package/dist/renderer/assets/{desktop-B-KVT10D.js → desktop-ul0Tpzyc.js} +1 -1
- package/dist/renderer/assets/{funnel-DA9qVdTy.js → funnel-Gu0E_hJ_.js} +1 -1
- package/dist/renderer/assets/{heart-DuEV0ZRJ.js → heart-DsdofOHf.js} +1 -1
- package/dist/renderer/assets/{index-Biz-aexG.js → index-BD3aCyBa.js} +3 -3
- package/dist/renderer/assets/{index-BgflqkCN.js → index-pJUFobU7.js} +1 -1
- package/dist/renderer/assets/{pencil-DBDxeNmO.js → pencil-DbKmV8nD.js} +1 -1
- package/dist/renderer/assets/{play-IzlP83_7.js → play-BDMsRxSm.js} +1 -1
- package/dist/renderer/assets/{plug-CuT-qFnW.js → plug-t2dMl78-.js} +1 -1
- package/dist/renderer/assets/{plus-DEqgkn63.js → plus-BUb6zOAe.js} +1 -1
- package/dist/renderer/assets/projects-4F6D_Q8t.js +1 -0
- package/dist/renderer/assets/{save-D4sRo07y.js → save-C-_5rQdv.js} +1 -1
- package/dist/renderer/assets/{search-DbPZLuV8.js → search-R3ekHFPM.js} +1 -1
- package/dist/renderer/assets/{server-D1jUQmwN.js → server-BTuvHf5n.js} +1 -1
- package/dist/renderer/assets/{session-utils-Aife8ep2.js → session-utils-ClX6VPFG.js} +1 -1
- package/dist/renderer/assets/{sessions-DaH3H7gC.js → sessions-AFKIC-ub.js} +1 -1
- package/dist/renderer/assets/{shield-check-BGwUFWNr.js → shield-check-CqMW8CHe.js} +1 -1
- package/dist/renderer/assets/{trash-2-CIFBioBa.js → trash-2-BNLcHyUw.js} +1 -1
- package/dist/renderer/assets/{user-CnKcvHdo.js → user-BCCN8FYK.js} +1 -1
- package/dist/renderer/assets/{wifi-off-ClO53WGa.js → wifi-off-BsNsx3oX.js} +1 -1
- package/dist/renderer/index.html +1 -1
- package/dist-electron/electron/agent-runtime-detector.test.js +64 -0
- package/dist-electron/electron/architecture-docs.test.js +56 -0
- package/dist-electron/electron/channel-content.test.js +37 -0
- package/dist-electron/electron/lac-cli.test.js +297 -4
- package/dist-electron/electron/local-core-acp-content.test.js +39 -0
- package/dist-electron/electron/local-core-contracts.test.js +67 -0
- package/dist-electron/electron/local-core-refactor.test.js +789 -3
- package/dist-electron/electron/plugin-kernel.test.js +108 -0
- package/dist-electron/electron/renderer-packaging.test.js +77 -0
- package/dist-electron/electron/workspace-task-store.test.js +181 -0
- package/dist-electron/packages/contracts/src/local-core.js +110 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +67 -6
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-content.js +25 -4
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-permission-lifecycle.js +76 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-progress.js +201 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-response-processor.js +3 -2
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +29 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +74 -46
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +112 -210
- package/dist-electron/services/local-ai-core/src/acp/local-core-slash-commands.js +60 -0
- package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +5 -48
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +83 -28
- package/dist-electron/services/local-ai-core/src/channel/lark/runtime-state.js +11 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/content.js +23 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/file-utils.js +13 -1
- package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +31 -29
- package/dist-electron/services/local-ai-core/src/cli/lac.js +22 -17
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +1 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js +9 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +221 -10
- package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +39 -9
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +1 -0
- package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +1 -0
- package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +439 -0
- package/dist-electron/services/local-ai-core/src/runtime/server.js +208 -303
- package/dist-electron/services/local-ai-core/src/scheduler/job-id.js +15 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduler-service.js +30 -5
- package/dist-electron/shared/desktop.js +34 -8
- package/dist-electron/src/pages/Threads/thread-chat-message-blocks.js +187 -0
- package/dist-electron/src/pages/Threads/thread-chat-model.js +58 -0
- package/dist-electron/src/pages/Threads/thread-chat-page-state.js +96 -0
- package/dist-electron/src/pages/Threads/thread-chat-permission.js +18 -0
- package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +347 -0
- package/package.json +4 -2
- package/dist/renderer/assets/ThreadChat-BotD0gKQ.js +0 -23
- package/dist/renderer/assets/desktop-CVibRyAw.js +0 -4
- package/dist/renderer/assets/projects-DDtDN1rc.js +0 -1
|
@@ -39,6 +39,7 @@ const node_crypto_1 = require("node:crypto");
|
|
|
39
39
|
const node_fs_1 = require("node:fs");
|
|
40
40
|
const node_path_1 = require("node:path");
|
|
41
41
|
const desktop_js_1 = require("../../../../../shared/desktop.js");
|
|
42
|
+
const content_js_1 = require("../shared/content.js");
|
|
42
43
|
const file_utils_js_1 = require("../shared/file-utils.js");
|
|
43
44
|
const cards_js_1 = require("./cards.js");
|
|
44
45
|
const config_js_1 = require("./config.js");
|
|
@@ -46,6 +47,8 @@ const registration_js_1 = require("./registration.js");
|
|
|
46
47
|
const runtime_state_js_1 = require("./runtime-state.js");
|
|
47
48
|
const PAIRING_EXPIRY_MS = 10 * 60 * 1000;
|
|
48
49
|
const LARK_MAX_UPLOAD_FILE_SIZE = 30 * 1024 * 1024;
|
|
50
|
+
const LARK_FINAL_PATCH_INTERVAL_MS = 900;
|
|
51
|
+
const LARK_PROGRESS_PATCH_INTERVAL_MS = 3000;
|
|
49
52
|
class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
50
53
|
options;
|
|
51
54
|
// Lark returns 200340 when card action events are not enabled in the app's
|
|
@@ -245,6 +248,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
245
248
|
const file = await (0, file_utils_js_1.prepareChannelFile)({
|
|
246
249
|
path: part.path,
|
|
247
250
|
fileName: part.fileName,
|
|
251
|
+
workspacePath: typeof part.metadata?.workspacePath === 'string' ? part.metadata.workspacePath : undefined,
|
|
248
252
|
maxBytes: LARK_MAX_UPLOAD_FILE_SIZE,
|
|
249
253
|
platformLabel: 'Lark',
|
|
250
254
|
});
|
|
@@ -474,9 +478,8 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
474
478
|
}
|
|
475
479
|
const existingMessageId = (0, runtime_state_js_1.getLarkRenderedMessageId)(turn, rendered);
|
|
476
480
|
const shouldThrottle = event.type === 'update_message' &&
|
|
477
|
-
rendered.isFinal &&
|
|
478
481
|
existingMessageId &&
|
|
479
|
-
Date.now() - (turn.lastPatchedAtByMessageId[existingMessageId] || 0) <
|
|
482
|
+
Date.now() - (turn.lastPatchedAtByMessageId[existingMessageId] || 0) < (rendered.isFinal ? LARK_FINAL_PATCH_INTERVAL_MS : LARK_PROGRESS_PATCH_INTERVAL_MS);
|
|
480
483
|
this.options.log?.(`localcore-lark bridge event type=${event.type} sessionKey=${sessionKey} hasMessageId=${Boolean(existingMessageId)} throttle=${shouldThrottle}`);
|
|
481
484
|
if (shouldThrottle) {
|
|
482
485
|
return;
|
|
@@ -619,6 +622,10 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
619
622
|
if (slashCommand?.name === 'new') {
|
|
620
623
|
const title = slashCommand.args.join(' ').trim() || `${input.displayName || 'Lark'} ${new Date().toLocaleTimeString()}`;
|
|
621
624
|
const nextThread = await router.createThread(input.workspaceId, title);
|
|
625
|
+
const inheritedMode = this.options.store.getThreadRow?.(threadId)?.agent_mode || '';
|
|
626
|
+
if (inheritedMode && inheritedMode !== 'default') {
|
|
627
|
+
this.options.store.updateThreadAgentMode?.(nextThread.id, inheritedMode);
|
|
628
|
+
}
|
|
622
629
|
const now = new Date().toISOString();
|
|
623
630
|
this.options.store.updateAuthorizedUserThread(input.workspaceId, input.platformUserId, nextThread.id, platformKey);
|
|
624
631
|
this.options.store.upsertPlatformThreadBinding({
|
|
@@ -649,8 +656,10 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
649
656
|
return { paired: true, threadId };
|
|
650
657
|
}
|
|
651
658
|
this.options.store.clearPlatformThreadMessageId(input.workspaceId, input.chatId, input.platformUserId);
|
|
652
|
-
const wrappedText =
|
|
653
|
-
|
|
659
|
+
const wrappedText = slashCommand
|
|
660
|
+
? input.text
|
|
661
|
+
: (0, desktop_js_1.wrapUserMessageWithSchedulerProtocol)(input.text);
|
|
662
|
+
await router.sendThreadMessage(threadId, (0, content_js_1.createChannelThreadMessageInput)(wrappedText, input.contentParts));
|
|
654
663
|
return { paired: true, threadId };
|
|
655
664
|
}
|
|
656
665
|
close() {
|
|
@@ -857,15 +866,24 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
857
866
|
}
|
|
858
867
|
}
|
|
859
868
|
}
|
|
869
|
+
if (messageType === 'file') {
|
|
870
|
+
const fileKey = String(parsedContent.file_key || '').trim();
|
|
871
|
+
if (fileKey) {
|
|
872
|
+
try {
|
|
873
|
+
contentParts.push(await this.downloadMessageFile(workspaceId, String(message.message_id || ''), fileKey, String(parsedContent.file_name || parsedContent.name || '').trim(), instanceId));
|
|
874
|
+
}
|
|
875
|
+
catch (error) {
|
|
876
|
+
const errorText = `[File download failed: ${error instanceof Error ? error.message : String(error)}]`;
|
|
877
|
+
contentParts.push({ type: 'text', text: errorText });
|
|
878
|
+
this.options.log?.(`localcore-lark file download failed for ${workspaceId}: message=${String(message.message_id || '')} fileKey=${fileKey} error=${error instanceof Error ? error.message : String(error)}`);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
}
|
|
860
882
|
if (contentParts.length === 0) {
|
|
861
883
|
this.options.log?.(`localcore-lark ignored unsupported message for ${workspaceId}: type=${String(message.message_type || 'unknown')} contentKeys=${JSON.stringify(Object.keys(parsedContent))}`);
|
|
862
884
|
return;
|
|
863
885
|
}
|
|
864
|
-
const displayText = text || (contentParts
|
|
865
|
-
.filter((part) => part.type === 'text')
|
|
866
|
-
.map((part) => part.text)
|
|
867
|
-
.join('\n\n')
|
|
868
|
-
.trim());
|
|
886
|
+
const displayText = text || this.summarizeInboundContentParts(contentParts);
|
|
869
887
|
const platformUserId = String(sender.sender_id?.user_id || sender.sender_id?.open_id || '').trim();
|
|
870
888
|
const chatId = String(message.chat_id || platformUserId).trim();
|
|
871
889
|
if (!platformUserId || !chatId) {
|
|
@@ -887,25 +905,6 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
887
905
|
contentParts,
|
|
888
906
|
});
|
|
889
907
|
}
|
|
890
|
-
createWrappedContentParts(wrappedText, parts) {
|
|
891
|
-
const nonTextParts = Array.isArray(parts)
|
|
892
|
-
? parts.filter((part) => part.type !== 'text')
|
|
893
|
-
: [];
|
|
894
|
-
return [
|
|
895
|
-
{ type: 'text', text: wrappedText },
|
|
896
|
-
...nonTextParts,
|
|
897
|
-
];
|
|
898
|
-
}
|
|
899
|
-
createThreadMessageInput(wrappedText, parts) {
|
|
900
|
-
const hasNonTextPart = Array.isArray(parts) && parts.some((part) => part.type !== 'text');
|
|
901
|
-
if (!hasNonTextPart) {
|
|
902
|
-
return wrappedText;
|
|
903
|
-
}
|
|
904
|
-
return {
|
|
905
|
-
displayText: wrappedText,
|
|
906
|
-
contentParts: this.createWrappedContentParts(wrappedText, parts),
|
|
907
|
-
};
|
|
908
|
-
}
|
|
909
908
|
async downloadMessageImage(workspaceId, messageId, imageKey, instanceId) {
|
|
910
909
|
const state = this.resolveRuntimeState(workspaceId, instanceId).state;
|
|
911
910
|
if (!state?.client) {
|
|
@@ -935,6 +934,58 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
935
934
|
fileName: `${imageKey}.${this.sniffImageExtension(buffer)}`,
|
|
936
935
|
};
|
|
937
936
|
}
|
|
937
|
+
async downloadMessageFile(workspaceId, messageId, fileKey, fileName, instanceId) {
|
|
938
|
+
const state = this.resolveRuntimeState(workspaceId, instanceId).state;
|
|
939
|
+
if (!state?.client) {
|
|
940
|
+
throw new Error('Lark client is not connected');
|
|
941
|
+
}
|
|
942
|
+
if (!messageId) {
|
|
943
|
+
throw new Error('Lark file message is missing message_id');
|
|
944
|
+
}
|
|
945
|
+
const resource = await state.client.im.messageResource.get({
|
|
946
|
+
path: {
|
|
947
|
+
message_id: messageId,
|
|
948
|
+
file_key: fileKey,
|
|
949
|
+
},
|
|
950
|
+
params: {
|
|
951
|
+
type: 'file',
|
|
952
|
+
},
|
|
953
|
+
});
|
|
954
|
+
const buffer = await this.readLarkResourceBuffer(resource);
|
|
955
|
+
if (buffer.length === 0) {
|
|
956
|
+
throw new Error('Lark file resource is empty');
|
|
957
|
+
}
|
|
958
|
+
return {
|
|
959
|
+
type: 'file',
|
|
960
|
+
data: buffer.toString('base64'),
|
|
961
|
+
mimeType: this.extractHeaderMimeType(resource?.headers) || 'application/octet-stream',
|
|
962
|
+
fileName: fileName || fileKey,
|
|
963
|
+
size: buffer.length,
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
summarizeInboundContentParts(parts) {
|
|
967
|
+
const text = parts
|
|
968
|
+
.filter((part) => part.type === 'text')
|
|
969
|
+
.map((part) => part.text)
|
|
970
|
+
.filter(Boolean)
|
|
971
|
+
.join('\n\n')
|
|
972
|
+
.trim();
|
|
973
|
+
if (text)
|
|
974
|
+
return text;
|
|
975
|
+
const attachmentSummary = parts
|
|
976
|
+
.map((part) => {
|
|
977
|
+
if (part.type === 'image') {
|
|
978
|
+
return '[Image]';
|
|
979
|
+
}
|
|
980
|
+
if (part.type === 'file') {
|
|
981
|
+
return part.fileName ? `[File: ${part.fileName}]` : '[File]';
|
|
982
|
+
}
|
|
983
|
+
return '';
|
|
984
|
+
})
|
|
985
|
+
.filter(Boolean)
|
|
986
|
+
.join('\n');
|
|
987
|
+
return attachmentSummary;
|
|
988
|
+
}
|
|
938
989
|
async readLarkResourceBuffer(resource) {
|
|
939
990
|
const readable = resource?.getReadableStream?.();
|
|
940
991
|
if (!readable || typeof readable.on !== 'function') {
|
|
@@ -1052,6 +1103,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1052
1103
|
return this.larkModulePromise;
|
|
1053
1104
|
}
|
|
1054
1105
|
async sendTextAsCard(state, chatId, text, buttonRows = [], sessionKey, threadId) {
|
|
1106
|
+
const startedAt = Date.now();
|
|
1055
1107
|
const response = await state.client.im.message.create({
|
|
1056
1108
|
params: {
|
|
1057
1109
|
receive_id_type: this.resolveReceiveIdType(chatId),
|
|
@@ -1062,6 +1114,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1062
1114
|
content: JSON.stringify((0, cards_js_1.buildInteractiveCard)(text, buttonRows, sessionKey, threadId)),
|
|
1063
1115
|
},
|
|
1064
1116
|
});
|
|
1117
|
+
this.options.log?.(`localcore-lark card create took ${Date.now() - startedAt}ms textBytes=${Buffer.byteLength(text || '', 'utf8')}`);
|
|
1065
1118
|
return String(response?.data?.message_id || '').trim();
|
|
1066
1119
|
}
|
|
1067
1120
|
resolveReceiveIdType(receiveId) {
|
|
@@ -1092,6 +1145,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1092
1145
|
}
|
|
1093
1146
|
}
|
|
1094
1147
|
async patchTextCard(state, messageId, text, buttonRows = [], sessionKey, threadId) {
|
|
1148
|
+
const startedAt = Date.now();
|
|
1095
1149
|
await state.client.im.message.patch({
|
|
1096
1150
|
path: {
|
|
1097
1151
|
message_id: messageId,
|
|
@@ -1100,6 +1154,7 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
|
|
|
1100
1154
|
content: JSON.stringify((0, cards_js_1.buildInteractiveCard)(text, buttonRows, sessionKey, threadId)),
|
|
1101
1155
|
},
|
|
1102
1156
|
});
|
|
1157
|
+
this.options.log?.(`localcore-lark card patch took ${Date.now() - startedAt}ms message=${messageId} textBytes=${Buffer.byteLength(text || '', 'utf8')}`);
|
|
1103
1158
|
}
|
|
1104
1159
|
generatePairingCode() {
|
|
1105
1160
|
return String((0, node_crypto_1.randomInt)(100000, 1000000));
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createLarkTurnState = createLarkTurnState;
|
|
4
4
|
exports.foldToolResultForLark = foldToolResultForLark;
|
|
5
|
+
exports.isPendingToolProgressForLark = isPendingToolProgressForLark;
|
|
5
6
|
exports.consumeLarkBridgeEvent = consumeLarkBridgeEvent;
|
|
6
7
|
exports.renderLarkBridgeEventMessage = renderLarkBridgeEventMessage;
|
|
7
8
|
exports.getLarkRenderedMessageId = getLarkRenderedMessageId;
|
|
@@ -33,6 +34,10 @@ function foldToolResultForLark(content) {
|
|
|
33
34
|
return normalized;
|
|
34
35
|
return parts.slice(0, 2).join(' - ');
|
|
35
36
|
}
|
|
37
|
+
function isPendingToolProgressForLark(content) {
|
|
38
|
+
const normalized = foldToolResultForLark(content).toLowerCase();
|
|
39
|
+
return normalized.startsWith('🔧 ') && normalized.includes(' - pending');
|
|
40
|
+
}
|
|
36
41
|
function consumeLarkBridgeEvent(turn, event, options) {
|
|
37
42
|
const content = foldToolResultForLark(String(event.content || '').trim());
|
|
38
43
|
if (event.type === 'typing_start') {
|
|
@@ -98,6 +103,9 @@ function renderLarkBridgeEventMessage(turn, event) {
|
|
|
98
103
|
return renderProgressMessage(event.previewHandle || 'thinking-preview', content);
|
|
99
104
|
}
|
|
100
105
|
if (content.startsWith('🔧 ')) {
|
|
106
|
+
if (isPendingToolProgressForLark(content)) {
|
|
107
|
+
return { key: 'noop', text: '', buttonRows: [], isFinal: false };
|
|
108
|
+
}
|
|
101
109
|
return renderProgressMessage(progressKey('tool', event), content);
|
|
102
110
|
}
|
|
103
111
|
return {
|
|
@@ -116,6 +124,9 @@ function renderLarkBridgeEventMessage(turn, event) {
|
|
|
116
124
|
return renderProgressMessage(progressKey('thinking', event), content);
|
|
117
125
|
}
|
|
118
126
|
if (content.startsWith('🔧 ')) {
|
|
127
|
+
if (isPendingToolProgressForLark(content)) {
|
|
128
|
+
return { key: 'noop', text: '', buttonRows: [], isFinal: false };
|
|
129
|
+
}
|
|
119
130
|
return renderProgressMessage(progressKey('tool', event), content);
|
|
120
131
|
}
|
|
121
132
|
if (content.startsWith('⏳ ') || content.startsWith('📤 ')) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createWrappedChannelContentParts = createWrappedChannelContentParts;
|
|
4
|
+
exports.createChannelThreadMessageInput = createChannelThreadMessageInput;
|
|
5
|
+
function createWrappedChannelContentParts(wrappedText, parts) {
|
|
6
|
+
const nonTextParts = Array.isArray(parts)
|
|
7
|
+
? parts.filter((part) => part.type !== 'text')
|
|
8
|
+
: [];
|
|
9
|
+
return [
|
|
10
|
+
{ type: 'text', text: wrappedText },
|
|
11
|
+
...nonTextParts,
|
|
12
|
+
];
|
|
13
|
+
}
|
|
14
|
+
function createChannelThreadMessageInput(wrappedText, parts) {
|
|
15
|
+
const hasNonTextPart = Array.isArray(parts) && parts.some((part) => part.type !== 'text');
|
|
16
|
+
if (!hasNonTextPart) {
|
|
17
|
+
return wrappedText;
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
displayText: wrappedText,
|
|
21
|
+
contentParts: createWrappedChannelContentParts(wrappedText, parts),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.prepareChannelFile = prepareChannelFile;
|
|
4
|
+
exports.resolveChannelFilePath = resolveChannelFilePath;
|
|
4
5
|
exports.sanitizeChannelFileName = sanitizeChannelFileName;
|
|
5
6
|
const promises_1 = require("node:fs/promises");
|
|
6
7
|
const node_path_1 = require("node:path");
|
|
7
8
|
async function prepareChannelFile(input) {
|
|
8
|
-
const filePath =
|
|
9
|
+
const filePath = resolveChannelFilePath(input.path, input.workspacePath);
|
|
9
10
|
if (!filePath) {
|
|
10
11
|
throw new Error('Missing file path');
|
|
11
12
|
}
|
|
@@ -27,6 +28,17 @@ async function prepareChannelFile(input) {
|
|
|
27
28
|
fileSize: fileStat.size,
|
|
28
29
|
};
|
|
29
30
|
}
|
|
31
|
+
function resolveChannelFilePath(filePath, workspacePath) {
|
|
32
|
+
const normalized = String(filePath || '').trim();
|
|
33
|
+
if (!normalized) {
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
if ((0, node_path_1.isAbsolute)(normalized)) {
|
|
37
|
+
return normalized;
|
|
38
|
+
}
|
|
39
|
+
const workspaceRoot = String(workspacePath || '').trim();
|
|
40
|
+
return workspaceRoot ? (0, node_path_1.resolve)(workspaceRoot, normalized) : normalized;
|
|
41
|
+
}
|
|
30
42
|
function sanitizeChannelFileName(fileName) {
|
|
31
43
|
const normalized = String(fileName || '').trim().replace(/[\/\\]+/g, '_');
|
|
32
44
|
return normalized || 'file';
|
package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js
CHANGED
|
@@ -4,12 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.LocalCoreWeixinGateway = void 0;
|
|
7
|
+
exports.createWeixinAttachmentContentPart = createWeixinAttachmentContentPart;
|
|
7
8
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
8
9
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
11
|
const node_events_1 = require("node:events");
|
|
11
12
|
const node_crypto_2 = require("node:crypto");
|
|
12
13
|
const desktop_js_1 = require("../../../../../shared/desktop.js");
|
|
14
|
+
const content_js_1 = require("../shared/content.js");
|
|
13
15
|
const file_utils_js_1 = require("../shared/file-utils.js");
|
|
14
16
|
const config_js_1 = require("./config.js");
|
|
15
17
|
const transport_js_1 = require("./transport.js");
|
|
@@ -97,6 +99,23 @@ function splitTextByUtf8Bytes(text, maxBytes) {
|
|
|
97
99
|
pushCurrent();
|
|
98
100
|
return chunks;
|
|
99
101
|
}
|
|
102
|
+
function createWeixinAttachmentContentPart(att) {
|
|
103
|
+
if (att.kind === 'image') {
|
|
104
|
+
if (!att.data)
|
|
105
|
+
return null;
|
|
106
|
+
return {
|
|
107
|
+
type: 'image',
|
|
108
|
+
data: att.data,
|
|
109
|
+
mimeType: att.mimeType,
|
|
110
|
+
fileName: att.name,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
type: 'file',
|
|
115
|
+
path: att.path,
|
|
116
|
+
fileName: att.name,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
100
119
|
function truncateTextByUtf8Bytes(text, maxBytes) {
|
|
101
120
|
const normalized = String(text || '').replace(/\r\n/g, '\n').trim();
|
|
102
121
|
if (utf8ByteLength(normalized) <= maxBytes)
|
|
@@ -624,6 +643,10 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
624
643
|
if (slashCommand?.name === 'new') {
|
|
625
644
|
const title = slashCommand.args.join(' ').trim() || `${input.displayName || 'WeChat'} ${new Date().toLocaleTimeString()}`;
|
|
626
645
|
const nextThread = await router.createThread(input.workspaceId, title);
|
|
646
|
+
const inheritedMode = this.options.store.getThreadRow?.(threadId)?.agent_mode || '';
|
|
647
|
+
if (inheritedMode && inheritedMode !== 'default') {
|
|
648
|
+
this.options.store.updateThreadAgentMode?.(nextThread.id, inheritedMode);
|
|
649
|
+
}
|
|
627
650
|
const now = new Date().toISOString();
|
|
628
651
|
this.options.store.updateAuthorizedUserThread(input.workspaceId, input.platformUserId, nextThread.id, platformKey);
|
|
629
652
|
this.options.store.upsertPlatformThreadBinding({
|
|
@@ -657,8 +680,10 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
657
680
|
return { paired: true, threadId };
|
|
658
681
|
}
|
|
659
682
|
this.options.store.updatePlatformThreadMessageId(input.workspaceId, input.chatId, input.platformUserId, input.contextToken || input.messageId, platformKey);
|
|
660
|
-
const wrappedText =
|
|
661
|
-
|
|
683
|
+
const wrappedText = slashCommand
|
|
684
|
+
? input.text
|
|
685
|
+
: (0, desktop_js_1.wrapUserMessageWithSchedulerProtocol)(input.text);
|
|
686
|
+
await router.sendThreadMessage(threadId, (0, content_js_1.createChannelThreadMessageInput)(wrappedText, input.contentParts));
|
|
662
687
|
return { paired: true, threadId };
|
|
663
688
|
}
|
|
664
689
|
// ==================== Private: Bindings ====================
|
|
@@ -825,14 +850,9 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
825
850
|
if (att) {
|
|
826
851
|
attachmentText += attachmentText ? '\n' : '';
|
|
827
852
|
attachmentText += att.kind === 'image' ? `[Image: ${att.path}]` : `[File "${att.name}": ${att.path}]`;
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
data: att.data,
|
|
832
|
-
mimeType: att.mimeType,
|
|
833
|
-
fileName: att.name,
|
|
834
|
-
});
|
|
835
|
-
}
|
|
853
|
+
const part = createWeixinAttachmentContentPart(att);
|
|
854
|
+
if (part)
|
|
855
|
+
attachmentParts.push(part);
|
|
836
856
|
}
|
|
837
857
|
}
|
|
838
858
|
catch (dlErr) {
|
|
@@ -906,6 +926,7 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
906
926
|
const file = await (0, file_utils_js_1.prepareChannelFile)({
|
|
907
927
|
path: part.path,
|
|
908
928
|
fileName: part.fileName,
|
|
929
|
+
workspacePath: typeof part.metadata?.workspacePath === 'string' ? part.metadata.workspacePath : undefined,
|
|
909
930
|
maxBytes: WEIXIN_MAX_UPLOAD_FILE_SIZE,
|
|
910
931
|
platformLabel: 'WeChat',
|
|
911
932
|
});
|
|
@@ -1017,25 +1038,6 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
|
|
|
1017
1038
|
mimeType: kind === 'image' ? this.mimeTypeForImageExt(ext) : undefined,
|
|
1018
1039
|
};
|
|
1019
1040
|
}
|
|
1020
|
-
createWrappedContentParts(wrappedText, parts) {
|
|
1021
|
-
const nonTextParts = Array.isArray(parts)
|
|
1022
|
-
? parts.filter((part) => part.type !== 'text')
|
|
1023
|
-
: [];
|
|
1024
|
-
return [
|
|
1025
|
-
{ type: 'text', text: wrappedText },
|
|
1026
|
-
...nonTextParts,
|
|
1027
|
-
];
|
|
1028
|
-
}
|
|
1029
|
-
createThreadMessageInput(wrappedText, parts) {
|
|
1030
|
-
const hasNonTextPart = Array.isArray(parts) && parts.some((part) => part.type !== 'text');
|
|
1031
|
-
if (!hasNonTextPart) {
|
|
1032
|
-
return wrappedText;
|
|
1033
|
-
}
|
|
1034
|
-
return {
|
|
1035
|
-
displayText: wrappedText,
|
|
1036
|
-
contentParts: this.createWrappedContentParts(wrappedText, parts),
|
|
1037
|
-
};
|
|
1038
|
-
}
|
|
1039
1041
|
mimeTypeForImageExt(ext) {
|
|
1040
1042
|
if (ext === '.jpg')
|
|
1041
1043
|
return 'image/jpeg';
|
|
@@ -5,6 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.runCli = runCli;
|
|
7
7
|
const node_process_1 = __importDefault(require("node:process"));
|
|
8
|
+
const index_js_1 = require("../../../../packages/contracts/src/index.js");
|
|
9
|
+
const job_id_js_1 = require("../scheduler/job-id.js");
|
|
8
10
|
const DEFAULT_BASE_URL = 'http://127.0.0.1:9831/api/local/v1';
|
|
9
11
|
async function runCli(argv, env = node_process_1.default.env, io = node_process_1.default) {
|
|
10
12
|
try {
|
|
@@ -51,7 +53,8 @@ async function runCli(argv, env = node_process_1.default.env, io = node_process_
|
|
|
51
53
|
async function handleChannelSendFile(flags, env, io, json) {
|
|
52
54
|
const context = resolveContext(flags, env);
|
|
53
55
|
const filePath = getRequiredFlag(flags, 'path');
|
|
54
|
-
const
|
|
56
|
+
const rawPlatform = getFlag(flags, 'platform') || context.platform;
|
|
57
|
+
const platform = rawPlatform ? (0, index_js_1.normalizeChannelPlatform)(rawPlatform) : '';
|
|
55
58
|
if (!platform) {
|
|
56
59
|
throw new Error('channel send-file requires a platform. Set LOCAL_AI_PLATFORM or pass --platform.');
|
|
57
60
|
}
|
|
@@ -72,6 +75,7 @@ async function handleChannelSendFile(flags, env, io, json) {
|
|
|
72
75
|
type: 'file',
|
|
73
76
|
path: filePath,
|
|
74
77
|
fileName: getFlag(flags, 'name') || undefined,
|
|
78
|
+
metadata: context.workspacePath ? { workspacePath: context.workspacePath } : undefined,
|
|
75
79
|
}],
|
|
76
80
|
});
|
|
77
81
|
const file = result.attachments?.[0];
|
|
@@ -113,8 +117,8 @@ async function handleAdd(flags, env, io, json) {
|
|
|
113
117
|
description,
|
|
114
118
|
enabled: true,
|
|
115
119
|
});
|
|
116
|
-
print(json, io.stdout, job, [
|
|
117
|
-
`Created scheduler job ${job.id}`,
|
|
120
|
+
print(json, io.stdout, presentJob(job), [
|
|
121
|
+
`Created scheduler job ${(0, job_id_js_1.toPublicScheduledJobId)(job.id)}`,
|
|
118
122
|
`Schedule: ${job.cronExpr || ''}`,
|
|
119
123
|
`Execution mode: ${job.executionMode}`,
|
|
120
124
|
`Description: ${job.description}`,
|
|
@@ -132,7 +136,7 @@ async function handleList(flags, env, io, json) {
|
|
|
132
136
|
const jobs = threadId
|
|
133
137
|
? response.jobs.filter((job) => job.route.threadId === threadId)
|
|
134
138
|
: response.jobs;
|
|
135
|
-
print(json, io.stdout, { jobs }, jobs.length === 0 ? 'No scheduler jobs.' : jobs.map(formatJobLine).join('\n'));
|
|
139
|
+
print(json, io.stdout, { jobs: jobs.map(presentJob) }, jobs.length === 0 ? 'No scheduler jobs.' : jobs.map(formatJobLine).join('\n'));
|
|
136
140
|
return 0;
|
|
137
141
|
}
|
|
138
142
|
async function handleInfo(jobId, flags, env, io, json) {
|
|
@@ -142,7 +146,7 @@ async function handleInfo(jobId, flags, env, io, json) {
|
|
|
142
146
|
const context = resolveContext(flags, env);
|
|
143
147
|
const job = await request(context.baseUrl, 'GET', `/scheduler/jobs/${encodeURIComponent(jobId)}`);
|
|
144
148
|
const runs = await request(context.baseUrl, 'GET', `/scheduler/jobs/${encodeURIComponent(jobId)}/runs`);
|
|
145
|
-
print(json, io.stdout, { job, runs: runs.runs }, formatJobDetails(job, runs.runs[0]));
|
|
149
|
+
print(json, io.stdout, { job: presentJob(job), runs: runs.runs }, formatJobDetails(job, runs.runs[0]));
|
|
146
150
|
return 0;
|
|
147
151
|
}
|
|
148
152
|
async function handleEdit(jobId, flags, env, io, json) {
|
|
@@ -168,14 +172,14 @@ async function handleEdit(jobId, flags, env, io, json) {
|
|
|
168
172
|
input.enabled = enabled;
|
|
169
173
|
}
|
|
170
174
|
if (executionMode) {
|
|
171
|
-
input.executionMode =
|
|
175
|
+
input.executionMode = (0, index_js_1.normalizeScheduledJobExecutionMode)(executionMode);
|
|
172
176
|
}
|
|
173
177
|
if (Object.keys(input).length === 0) {
|
|
174
178
|
throw new Error('scheduler edit requires at least one editable field.');
|
|
175
179
|
}
|
|
176
180
|
const context = resolveContext(flags, env);
|
|
177
181
|
const job = await request(context.baseUrl, 'PATCH', `/scheduler/jobs/${encodeURIComponent(jobId)}`, input);
|
|
178
|
-
print(json, io.stdout, job, `Updated scheduler job ${job.id}`);
|
|
182
|
+
print(json, io.stdout, presentJob(job), `Updated scheduler job ${(0, job_id_js_1.toPublicScheduledJobId)(job.id)}`);
|
|
179
183
|
return 0;
|
|
180
184
|
}
|
|
181
185
|
async function handleDelete(jobId, flags, env, io, json) {
|
|
@@ -223,6 +227,7 @@ function resolveContext(flags, env) {
|
|
|
223
227
|
return {
|
|
224
228
|
baseUrl: getFlag(flags, 'base-url') || String(env.LOCAL_AI_CORE_BASE || DEFAULT_BASE_URL),
|
|
225
229
|
workspaceId: getFlag(flags, 'workspace') || String(env.LOCAL_AI_WORKSPACE_ID || ''),
|
|
230
|
+
workspacePath: getFlag(flags, 'workspace-path') || String(env.LOCAL_AI_WORKSPACE_PATH || ''),
|
|
226
231
|
threadId: normalizeMaybeBooleanFlag(getFlag(flags, 'thread')) || String(env.LOCAL_AI_THREAD_ID || ''),
|
|
227
232
|
platform,
|
|
228
233
|
routeType: String(env.LOCAL_AI_ROUTE_TYPE || '') || (platform === 'lark' && chatId && platformUserId ? 'channel.chat' : ''),
|
|
@@ -284,13 +289,7 @@ function normalizeMaybeBooleanFlag(value) {
|
|
|
284
289
|
return value === 'true' ? '' : value;
|
|
285
290
|
}
|
|
286
291
|
function getExecutionMode(flags) {
|
|
287
|
-
return
|
|
288
|
-
}
|
|
289
|
-
function parseExecutionMode(value) {
|
|
290
|
-
if (value === 'same-thread' || value === 'side-thread') {
|
|
291
|
-
return value;
|
|
292
|
-
}
|
|
293
|
-
throw new Error('Flag --execution-mode must be same-thread or side-thread');
|
|
292
|
+
return (0, index_js_1.normalizeScheduledJobExecutionMode)(getFlag(flags, 'execution-mode'));
|
|
294
293
|
}
|
|
295
294
|
function print(asJson, output, payload, text) {
|
|
296
295
|
output.write(asJson ? `${JSON.stringify(payload, null, 2)}\n` : `${text}\n`);
|
|
@@ -304,16 +303,16 @@ function printUsage(output) {
|
|
|
304
303
|
' lac scheduler edit <job-id> [--cron "<expr>"] [--message "<text>"] [--desc "<label>"] [--enabled true|false] [--execution-mode same-thread|side-thread] [--json]',
|
|
305
304
|
' lac scheduler del <job-id> [--json]',
|
|
306
305
|
' lac scheduler run <job-id> [--json]',
|
|
307
|
-
' lac channel send-file --path "<file>" [--target <chat-or-user-id>] [--workspace <id>] [--platform lark] [--name <filename>] [--json]',
|
|
306
|
+
' lac channel send-file --path "<file>" [--target <chat-or-user-id>] [--workspace <id>] [--workspace-path <path>] [--platform lark] [--name <filename>] [--json]',
|
|
308
307
|
].join('\n') + '\n');
|
|
309
308
|
}
|
|
310
309
|
function formatJobLine(job) {
|
|
311
310
|
const schedule = job.triggerType === 'cron' ? job.cronExpr || '' : job.runAt || '';
|
|
312
|
-
return `${job.id} | ${job.enabled ? 'enabled' : 'disabled'} | ${job.executionMode} | ${schedule} | ${job.description}`;
|
|
311
|
+
return `${(0, job_id_js_1.toPublicScheduledJobId)(job.id)} | ${job.enabled ? 'enabled' : 'disabled'} | ${job.executionMode} | ${schedule} | ${job.description}`;
|
|
313
312
|
}
|
|
314
313
|
function formatJobDetails(job, latestRun) {
|
|
315
314
|
return [
|
|
316
|
-
`Job: ${job.id}`,
|
|
315
|
+
`Job: ${(0, job_id_js_1.toPublicScheduledJobId)(job.id)}`,
|
|
317
316
|
`Workspace: ${job.workspaceId}`,
|
|
318
317
|
`Platform: ${job.platform}`,
|
|
319
318
|
`Thread: ${job.route.threadId || ''}`,
|
|
@@ -325,6 +324,12 @@ function formatJobDetails(job, latestRun) {
|
|
|
325
324
|
latestRun ? `Latest run: ${latestRun.status} @ ${latestRun.triggeredAt}` : 'Latest run: none',
|
|
326
325
|
].join('\n');
|
|
327
326
|
}
|
|
327
|
+
function presentJob(job) {
|
|
328
|
+
return {
|
|
329
|
+
...job,
|
|
330
|
+
id: (0, job_id_js_1.toPublicScheduledJobId)(job.id),
|
|
331
|
+
};
|
|
332
|
+
}
|
|
328
333
|
function formatError(error) {
|
|
329
334
|
return error instanceof Error ? error.message : String(error);
|
|
330
335
|
}
|
|
@@ -163,6 +163,7 @@ function bootstrapLocalCoreRuntime(options) {
|
|
|
163
163
|
}
|
|
164
164
|
const agentPlugins = [
|
|
165
165
|
localCoreAgentPlugin,
|
|
166
|
+
(0, agent_localcore_acp_plugin_js_1.createBuiltinPiAgentPlugin)(),
|
|
166
167
|
(0, agent_localcore_acp_plugin_js_1.createBuiltinOpencodeAgentPlugin)(),
|
|
167
168
|
(0, agent_localcore_acp_plugin_js_1.createBuiltinCodexAgentPlugin)(),
|
|
168
169
|
(0, agent_localcore_acp_plugin_js_1.createBuiltinClaudeCodeAgentPlugin)(),
|
package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createBuiltinLocalCoreAcpAgentPlugin = createBuiltinLocalCoreAcpAgentPlugin;
|
|
4
4
|
exports.createBuiltinOpencodeAgentPlugin = createBuiltinOpencodeAgentPlugin;
|
|
5
|
+
exports.createBuiltinPiAgentPlugin = createBuiltinPiAgentPlugin;
|
|
5
6
|
exports.createBuiltinCodexAgentPlugin = createBuiltinCodexAgentPlugin;
|
|
6
7
|
exports.createBuiltinClaudeCodeAgentPlugin = createBuiltinClaudeCodeAgentPlugin;
|
|
7
8
|
exports.createBuiltinStaticAgentCapabilityPlugin = createBuiltinStaticAgentCapabilityPlugin;
|
|
@@ -86,6 +87,14 @@ function createBuiltinOpencodeAgentPlugin() {
|
|
|
86
87
|
displayName: 'OpenCode',
|
|
87
88
|
});
|
|
88
89
|
}
|
|
90
|
+
function createBuiltinPiAgentPlugin() {
|
|
91
|
+
return createBuiltinAgentPlugin({
|
|
92
|
+
pluginId: 'builtin.agent-pi',
|
|
93
|
+
agentType: 'pi',
|
|
94
|
+
match: (normalizedAgentType) => normalizedAgentType === 'pi',
|
|
95
|
+
displayName: 'Pi',
|
|
96
|
+
});
|
|
97
|
+
}
|
|
89
98
|
function createBuiltinCodexAgentPlugin() {
|
|
90
99
|
return createBuiltinAgentPlugin({
|
|
91
100
|
pluginId: 'builtin.agent-codex',
|