@foxden-app/foxclaw 0.7.3 → 0.10.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/.env.example +13 -0
- package/CHANGELOG.md +109 -0
- package/README.md +21 -1
- package/README_EN.md +21 -1
- package/dist/antigravity/adapter.d.ts +17 -0
- package/dist/antigravity/adapter.js +256 -0
- package/dist/antigravity/auth.d.ts +121 -0
- package/dist/antigravity/auth.js +896 -0
- package/dist/antigravity/client.d.ts +32 -0
- package/dist/antigravity/client.js +238 -0
- package/dist/antigravity/controller.d.ts +96 -0
- package/dist/antigravity/controller.js +1922 -0
- package/dist/antigravity/conversations.d.ts +29 -0
- package/dist/antigravity/conversations.js +289 -0
- package/dist/antigravity/events.d.ts +101 -0
- package/dist/antigravity/events.js +114 -0
- package/dist/antigravity/runtime.d.ts +47 -0
- package/dist/antigravity/runtime.js +82 -0
- package/dist/channels/telegram/telegram_channel_adapter.d.ts +10 -3
- package/dist/channels/telegram/telegram_channel_adapter.js +2 -1
- package/dist/channels/weixin/weixin_channel_adapter.d.ts +5 -1
- package/dist/codex_app/adapter.d.ts +20 -0
- package/dist/codex_app/adapter.js +213 -0
- package/dist/codex_app/client.d.ts +1 -1
- package/dist/codex_app/client.js +12 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.js +42 -0
- package/dist/controller/controller.d.ts +8 -5
- package/dist/controller/controller.js +38 -8
- package/dist/core/attachments.d.ts +11 -0
- package/dist/core/attachments.js +56 -0
- package/dist/core/engine_spi.d.ts +76 -0
- package/dist/core/engine_spi.js +1 -0
- package/dist/core/orchestrator.d.ts +101 -0
- package/dist/core/orchestrator.js +1404 -0
- package/dist/core/stream_preview.d.ts +29 -0
- package/dist/core/stream_preview.js +146 -0
- package/dist/core/turn_queue.d.ts +19 -0
- package/dist/core/turn_queue.js +41 -0
- package/dist/i18n.d.ts +6 -0
- package/dist/i18n.js +49 -0
- package/dist/main.js +146 -12
- package/dist/opencode/adapter.d.ts +11 -0
- package/dist/opencode/adapter.js +168 -0
- package/dist/store/database.d.ts +41 -0
- package/dist/store/database.js +242 -43
- package/dist/store/token_usage.d.ts +23 -0
- package/dist/store/token_usage.js +61 -0
- package/dist/telegram/api.js +30 -1
- package/dist/telegram/gateway.d.ts +4 -0
- package/dist/telegram/gateway.js +11 -0
- package/dist/types.d.ts +1 -0
- package/dist/update.d.ts +6 -0
- package/dist/update.js +78 -6
- package/dist/voice/tts.js +4 -2
- package/docs/devlogs//346/212/200/346/234/257/351/200/232/350/256/257/02./347/273/237/344/270/200/351/200/232/351/201/223/350/260/203/345/272/246/345/231/250/344/270/216/345/217/257/346/217/222/346/213/224/345/274/225/346/223/216SPI/357/274/232FoxClaw/344/273/216/345/215/225/344/275/223/350/265/260/345/220/221/345/244/232Agent/345/272/225/345/272/247.md +192 -0
- package/docs/devlogs//347/254/254/344/270/200/344/272/272/347/247/260/347/211/210/02./347/257/207/344/272/214_/345/275/223/344/270/200/344/270/252/346/241/245/346/216/245/345/231/250/345/274/200/345/247/213/345/255/246/344/274/232/345/220/254/346/207/202/346/211/200/346/234/211Agent.md +45 -0
- package/package.json +2 -2
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { formatSdkError } from './client.js';
|
|
3
|
+
import { buildAttachmentPrompt } from '../telegram/media.js';
|
|
4
|
+
export class OpencodeEngineAdapter {
|
|
5
|
+
client;
|
|
6
|
+
defaultModel;
|
|
7
|
+
id = 'opencode';
|
|
8
|
+
name = 'OpenCode (SDK)';
|
|
9
|
+
constructor(client, defaultModel) {
|
|
10
|
+
this.client = client;
|
|
11
|
+
this.defaultModel = defaultModel;
|
|
12
|
+
}
|
|
13
|
+
async listModels() {
|
|
14
|
+
if (!this.client.isConnected())
|
|
15
|
+
return [];
|
|
16
|
+
try {
|
|
17
|
+
const response = await this.client.getClient().provider.list();
|
|
18
|
+
if (response.error || !response.data)
|
|
19
|
+
return [];
|
|
20
|
+
const { all, connected, default: defaultMap } = response.data;
|
|
21
|
+
const models = [];
|
|
22
|
+
for (const providerId of connected) {
|
|
23
|
+
const provider = all.find((p) => p.id === providerId);
|
|
24
|
+
if (!provider)
|
|
25
|
+
continue;
|
|
26
|
+
const defaultForProvider = defaultMap[providerId];
|
|
27
|
+
for (const m of Object.values(provider.models)) {
|
|
28
|
+
const modelFullId = `${providerId}/${m.id}`;
|
|
29
|
+
models.push({
|
|
30
|
+
id: modelFullId,
|
|
31
|
+
name: `${provider.name} - ${m.name}`,
|
|
32
|
+
isDefault: m.id === defaultForProvider,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return models;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
executeTurn(request) {
|
|
43
|
+
const emitter = new EventEmitter();
|
|
44
|
+
let sessionId = request.threadId;
|
|
45
|
+
let cancelled = false;
|
|
46
|
+
let promptText = request.prompt;
|
|
47
|
+
if (request.stagedAttachments && request.stagedAttachments.length > 0 && !request.prompt.includes('Telegram attachments:')) {
|
|
48
|
+
promptText = buildAttachmentPrompt(request.prompt, request.stagedAttachments);
|
|
49
|
+
}
|
|
50
|
+
let finalResult = null;
|
|
51
|
+
let turnError = null;
|
|
52
|
+
const resultWaiters = [];
|
|
53
|
+
const resolveWaiters = (res) => {
|
|
54
|
+
while (resultWaiters.length > 0) {
|
|
55
|
+
resultWaiters.shift()(res);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const run = async () => {
|
|
59
|
+
try {
|
|
60
|
+
const sdk = this.client.getClient();
|
|
61
|
+
if (!sessionId) {
|
|
62
|
+
const createRes = await sdk.session.create({ directory: request.cwd });
|
|
63
|
+
if (createRes.error || !createRes.data) {
|
|
64
|
+
throw new Error(`Failed to create OpenCode session: ${formatSdkError(createRes.error)}`);
|
|
65
|
+
}
|
|
66
|
+
sessionId = createRes.data.id;
|
|
67
|
+
}
|
|
68
|
+
if (cancelled)
|
|
69
|
+
return;
|
|
70
|
+
let accumulatedResponse = '';
|
|
71
|
+
const onEvent = (ev) => {
|
|
72
|
+
if ('sessionId' in ev && ev.sessionId === sessionId) {
|
|
73
|
+
if (ev.kind === 'text') {
|
|
74
|
+
if (ev.delta) {
|
|
75
|
+
accumulatedResponse += ev.delta;
|
|
76
|
+
emitter.emit('delta', ev.delta);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else if (ev.kind === 'tool') {
|
|
80
|
+
emitter.emit('tool', {
|
|
81
|
+
name: ev.tool,
|
|
82
|
+
args: undefined,
|
|
83
|
+
output: undefined,
|
|
84
|
+
status: ev.status === 'running' ? 'running' : ev.status === 'error' ? 'failed' : 'completed',
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else if (ev.kind === 'idle') {
|
|
88
|
+
cleanup();
|
|
89
|
+
finalResult = {
|
|
90
|
+
kind: 'result',
|
|
91
|
+
status: 'SUCCESS',
|
|
92
|
+
response: accumulatedResponse,
|
|
93
|
+
conversationId: sessionId,
|
|
94
|
+
};
|
|
95
|
+
emitter.emit('result', finalResult);
|
|
96
|
+
resolveWaiters(finalResult);
|
|
97
|
+
}
|
|
98
|
+
else if (ev.kind === 'error') {
|
|
99
|
+
cleanup();
|
|
100
|
+
turnError = new Error(ev.message);
|
|
101
|
+
finalResult = {
|
|
102
|
+
kind: 'result',
|
|
103
|
+
status: 'ERROR',
|
|
104
|
+
response: ev.message,
|
|
105
|
+
conversationId: sessionId,
|
|
106
|
+
};
|
|
107
|
+
emitter.emit('result', finalResult);
|
|
108
|
+
emitter.emit('error', turnError);
|
|
109
|
+
resolveWaiters(finalResult);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const cleanup = () => {
|
|
114
|
+
this.client.off('event', onEvent);
|
|
115
|
+
};
|
|
116
|
+
this.client.on('event', onEvent);
|
|
117
|
+
let modelParam;
|
|
118
|
+
const targetModel = request.model || this.defaultModel;
|
|
119
|
+
if (targetModel && targetModel.includes('/')) {
|
|
120
|
+
const [pId, ...mRest] = targetModel.split('/');
|
|
121
|
+
modelParam = { providerID: pId, modelID: mRest.join('/') };
|
|
122
|
+
}
|
|
123
|
+
const promptRes = await sdk.session.promptAsync({
|
|
124
|
+
sessionID: sessionId,
|
|
125
|
+
directory: request.cwd,
|
|
126
|
+
parts: [{ type: 'text', text: promptText }],
|
|
127
|
+
...(modelParam ? { model: modelParam } : {}),
|
|
128
|
+
});
|
|
129
|
+
if (promptRes.error) {
|
|
130
|
+
cleanup();
|
|
131
|
+
turnError = new Error(formatSdkError(promptRes.error));
|
|
132
|
+
emitter.emit('error', turnError);
|
|
133
|
+
resolveWaiters(null);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
this.client.watchSessionUntilIdle(sessionId, request.cwd);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
turnError = err instanceof Error ? err : new Error(String(err));
|
|
141
|
+
emitter.emit('error', turnError);
|
|
142
|
+
resolveWaiters(null);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
void run();
|
|
146
|
+
return {
|
|
147
|
+
turnId: sessionId ?? undefined,
|
|
148
|
+
cancel: () => {
|
|
149
|
+
cancelled = true;
|
|
150
|
+
if (sessionId) {
|
|
151
|
+
void this.client.getClient().session.abort({ sessionID: sessionId }).catch(() => { });
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
waitForResult: async () => {
|
|
155
|
+
if (finalResult)
|
|
156
|
+
return finalResult;
|
|
157
|
+
if (turnError)
|
|
158
|
+
return null;
|
|
159
|
+
return new Promise((resolve) => {
|
|
160
|
+
resultWaiters.push(resolve);
|
|
161
|
+
});
|
|
162
|
+
},
|
|
163
|
+
on: (event, listener) => {
|
|
164
|
+
emitter.on(event, listener);
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
package/dist/store/database.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AccessPresetValue, ActiveTurnMessageMode, AppLocale, CachedThread, ChatSessionSettings, CollaborationModeValue, GuidedPlanSessionRecord, GuidedPlanSessionState, PendingAttachmentBatchRecord, PendingAttachmentBatchStatus, PendingApprovalRecord, QueuedTurnInputRecord, QueuedTurnInputStatus, ReasoningEffortValue, ThreadBinding } from '../types.js';
|
|
2
|
+
import type { CumulativeTokenTotals, CumulativeTokenUsageRecord, TokenUsageDelta } from './token_usage.js';
|
|
2
3
|
export interface ActiveTurnPreviewRecord {
|
|
3
4
|
turnId: string;
|
|
4
5
|
scopeId: string;
|
|
@@ -62,6 +63,12 @@ export declare class BridgeStore {
|
|
|
62
63
|
setBinding(chatId: string, threadId: string, cwd: string | null): void;
|
|
63
64
|
listBindings(): ThreadBinding[];
|
|
64
65
|
clearBinding(chatId: string): void;
|
|
66
|
+
getWatchedThread(chatId: string): string | null;
|
|
67
|
+
setWatchedThread(chatId: string, threadId: string | null): void;
|
|
68
|
+
listWatchedThreads(): Array<{
|
|
69
|
+
scopeId: string;
|
|
70
|
+
threadId: string;
|
|
71
|
+
}>;
|
|
65
72
|
getChatSettings(chatId: string): ChatSessionSettings | null;
|
|
66
73
|
setChatSettings(chatId: string, model: string | null, reasoningEffort: ReasoningEffortValue | null, locale?: AppLocale | null): void;
|
|
67
74
|
setChatLocale(chatId: string, locale: AppLocale): void;
|
|
@@ -69,6 +76,30 @@ export declare class BridgeStore {
|
|
|
69
76
|
setChatCollaborationMode(chatId: string, collaborationMode: CollaborationModeValue | null): void;
|
|
70
77
|
setChatServiceTier(chatId: string, serviceTier: string | null): void;
|
|
71
78
|
setChatActiveTurnMessageMode(chatId: string, activeTurnMessageMode: ActiveTurnMessageMode | null): void;
|
|
79
|
+
getActiveBackend(chatId: string): string | null;
|
|
80
|
+
setActiveBackend(chatId: string, backendId: string | null): void;
|
|
81
|
+
getScopeBackendBinding(scopeId: string, backendId: string): {
|
|
82
|
+
threadId: string;
|
|
83
|
+
cwd: string | null;
|
|
84
|
+
model?: string | null;
|
|
85
|
+
reasoningEffort?: string | null;
|
|
86
|
+
activeTurnMessageMode?: string | null;
|
|
87
|
+
serviceTier?: string | null;
|
|
88
|
+
accessPreset?: string | null;
|
|
89
|
+
} | null;
|
|
90
|
+
setScopeBackendBinding(scopeId: string, backendId: string, threadId: string, cwd: string | null, settings?: {
|
|
91
|
+
model?: string | null;
|
|
92
|
+
reasoningEffort?: string | null;
|
|
93
|
+
activeTurnMessageMode?: string | null;
|
|
94
|
+
serviceTier?: string | null;
|
|
95
|
+
accessPreset?: string | null;
|
|
96
|
+
} | null): void;
|
|
97
|
+
listScopeBackendBindings(scopeId: string): Array<{
|
|
98
|
+
backendId: string;
|
|
99
|
+
threadId: string;
|
|
100
|
+
cwd: string | null;
|
|
101
|
+
updatedAt: number;
|
|
102
|
+
}>;
|
|
72
103
|
findChatIdByThreadId(threadId: string): string | null;
|
|
73
104
|
findAllChatIdsByThreadId(threadId: string): string[];
|
|
74
105
|
countBindings(): number;
|
|
@@ -141,5 +172,15 @@ export declare class BridgeStore {
|
|
|
141
172
|
getCodexAuthPoolStats(): CodexAuthPoolStats;
|
|
142
173
|
setCodexAuthQuotaSnapshot(runtimeId: string, candidateName: string, accountId: string, quotaIdentityId: string, snapshot: Pick<CodexAuthQuotaSnapshotRecord, 'capturedAtMs' | 'planType' | 'primaryWindowDurationMins' | 'primaryRemainingPercent' | 'secondaryWindowDurationMins' | 'secondaryRemainingPercent'> & Partial<Pick<CodexAuthQuotaSnapshotRecord, 'primaryResetsAt' | 'secondaryResetsAt'>>): void;
|
|
143
174
|
listCodexAuthQuotaSnapshots(quotaIdentityIds: string[]): CodexAuthQuotaSnapshotRecord[];
|
|
175
|
+
recordTokenUsage(delta: TokenUsageDelta, backendId?: string): void;
|
|
176
|
+
setBackendCumulativeTokenUsage(usage: {
|
|
177
|
+
inputTokens: number;
|
|
178
|
+
outputTokens: number;
|
|
179
|
+
cachedTokens?: number;
|
|
180
|
+
totalTokens?: number;
|
|
181
|
+
turnsCount?: number;
|
|
182
|
+
}, backendId: string): void;
|
|
183
|
+
getCumulativeTokenUsage(backendId?: string): CumulativeTokenTotals;
|
|
184
|
+
getAllBackendTokenUsages(): CumulativeTokenUsageRecord[];
|
|
144
185
|
private ensureColumn;
|
|
145
186
|
}
|