@foxden-app/foxclaw 0.7.3 → 0.11.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 +22 -8
- package/CHANGELOG.md +134 -0
- package/README.md +21 -1
- package/README_EN.md +21 -1
- package/dist/antigravity/adapter.d.ts +18 -0
- package/dist/antigravity/adapter.js +394 -0
- package/dist/antigravity/auth.d.ts +126 -0
- package/dist/antigravity/auth.js +933 -0
- package/dist/antigravity/client.d.ts +32 -0
- package/dist/antigravity/client.js +244 -0
- package/dist/antigravity/controller.d.ts +101 -0
- package/dist/antigravity/controller.js +2007 -0
- package/dist/antigravity/conversations.d.ts +29 -0
- package/dist/antigravity/conversations.js +289 -0
- package/dist/antigravity/events.d.ts +102 -0
- package/dist/antigravity/events.js +143 -0
- package/dist/antigravity/runtime.d.ts +49 -0
- package/dist/antigravity/runtime.js +82 -0
- package/dist/antigravity/subagents.d.ts +66 -0
- package/dist/antigravity/subagents.js +459 -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 +14 -0
- package/dist/config.js +65 -16
- package/dist/controller/controller.d.ts +12 -5
- package/dist/controller/controller.js +109 -8
- package/dist/core/attachments.d.ts +11 -0
- package/dist/core/attachments.js +56 -0
- package/dist/core/engine_spi.d.ts +77 -0
- package/dist/core/engine_spi.js +1 -0
- package/dist/core/orchestrator.d.ts +106 -0
- package/dist/core/orchestrator.js +1556 -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 +375 -446
- package/dist/opencode/adapter.d.ts +11 -0
- package/dist/opencode/adapter.js +169 -0
- package/dist/opencode/controller.js +2 -2
- package/dist/store/database.d.ts +44 -0
- package/dist/store/database.js +275 -43
- package/dist/store/token_usage.d.ts +23 -0
- package/dist/store/token_usage.js +61 -0
- package/dist/telegram/api.d.ts +1 -0
- package/dist/telegram/api.js +80 -3
- package/dist/telegram/bot_home.js +5 -4
- package/dist/telegram/gateway.d.ts +4 -0
- package/dist/telegram/gateway.js +11 -0
- package/dist/types.d.ts +3 -0
- package/dist/update.d.ts +6 -0
- package/dist/update.js +95 -7
- 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,11 @@
|
|
|
1
|
+
import type { IEngineAdapter, EngineModel, EngineTurnRequest, EngineTurnExecution } from '../core/engine_spi.js';
|
|
2
|
+
import type { OpencodeAppClient } from './client.js';
|
|
3
|
+
export declare class OpencodeEngineAdapter implements IEngineAdapter {
|
|
4
|
+
private readonly client;
|
|
5
|
+
private readonly defaultModel?;
|
|
6
|
+
readonly id = "opencode";
|
|
7
|
+
readonly name = "OpenCode (SDK)";
|
|
8
|
+
constructor(client: OpencodeAppClient, defaultModel?: string | undefined);
|
|
9
|
+
listModels(): Promise<EngineModel[]>;
|
|
10
|
+
executeTurn(request: EngineTurnRequest): EngineTurnExecution;
|
|
11
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
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
|
+
emitter.emit('conversation', sessionId);
|
|
68
|
+
}
|
|
69
|
+
if (cancelled)
|
|
70
|
+
return;
|
|
71
|
+
let accumulatedResponse = '';
|
|
72
|
+
const onEvent = (ev) => {
|
|
73
|
+
if ('sessionId' in ev && ev.sessionId === sessionId) {
|
|
74
|
+
if (ev.kind === 'text') {
|
|
75
|
+
if (ev.delta) {
|
|
76
|
+
accumulatedResponse += ev.delta;
|
|
77
|
+
emitter.emit('delta', ev.delta);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else if (ev.kind === 'tool') {
|
|
81
|
+
emitter.emit('tool', {
|
|
82
|
+
name: ev.tool,
|
|
83
|
+
args: undefined,
|
|
84
|
+
output: undefined,
|
|
85
|
+
status: ev.status === 'running' ? 'running' : ev.status === 'error' ? 'failed' : 'completed',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
else if (ev.kind === 'idle') {
|
|
89
|
+
cleanup();
|
|
90
|
+
finalResult = {
|
|
91
|
+
kind: 'result',
|
|
92
|
+
status: 'SUCCESS',
|
|
93
|
+
response: accumulatedResponse,
|
|
94
|
+
conversationId: sessionId,
|
|
95
|
+
};
|
|
96
|
+
emitter.emit('result', finalResult);
|
|
97
|
+
resolveWaiters(finalResult);
|
|
98
|
+
}
|
|
99
|
+
else if (ev.kind === 'error') {
|
|
100
|
+
cleanup();
|
|
101
|
+
turnError = new Error(ev.message);
|
|
102
|
+
finalResult = {
|
|
103
|
+
kind: 'result',
|
|
104
|
+
status: 'ERROR',
|
|
105
|
+
response: ev.message,
|
|
106
|
+
conversationId: sessionId,
|
|
107
|
+
};
|
|
108
|
+
emitter.emit('result', finalResult);
|
|
109
|
+
emitter.emit('error', turnError);
|
|
110
|
+
resolveWaiters(finalResult);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const cleanup = () => {
|
|
115
|
+
this.client.off('event', onEvent);
|
|
116
|
+
};
|
|
117
|
+
this.client.on('event', onEvent);
|
|
118
|
+
let modelParam;
|
|
119
|
+
const targetModel = request.model || this.defaultModel;
|
|
120
|
+
if (targetModel && targetModel.includes('/')) {
|
|
121
|
+
const [pId, ...mRest] = targetModel.split('/');
|
|
122
|
+
modelParam = { providerID: pId, modelID: mRest.join('/') };
|
|
123
|
+
}
|
|
124
|
+
const promptRes = await sdk.session.promptAsync({
|
|
125
|
+
sessionID: sessionId,
|
|
126
|
+
directory: request.cwd,
|
|
127
|
+
parts: [{ type: 'text', text: promptText }],
|
|
128
|
+
...(modelParam ? { model: modelParam } : {}),
|
|
129
|
+
});
|
|
130
|
+
if (promptRes.error) {
|
|
131
|
+
cleanup();
|
|
132
|
+
turnError = new Error(formatSdkError(promptRes.error));
|
|
133
|
+
emitter.emit('error', turnError);
|
|
134
|
+
resolveWaiters(null);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
this.client.watchSessionUntilIdle(sessionId, request.cwd);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
turnError = err instanceof Error ? err : new Error(String(err));
|
|
142
|
+
emitter.emit('error', turnError);
|
|
143
|
+
resolveWaiters(null);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
void run();
|
|
147
|
+
return {
|
|
148
|
+
turnId: sessionId ?? undefined,
|
|
149
|
+
cancel: () => {
|
|
150
|
+
cancelled = true;
|
|
151
|
+
if (sessionId) {
|
|
152
|
+
void this.client.getClient().session.abort({ sessionID: sessionId }).catch(() => { });
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
waitForResult: async () => {
|
|
156
|
+
if (finalResult)
|
|
157
|
+
return finalResult;
|
|
158
|
+
if (turnError)
|
|
159
|
+
return null;
|
|
160
|
+
return new Promise((resolve) => {
|
|
161
|
+
resultWaiters.push(resolve);
|
|
162
|
+
});
|
|
163
|
+
},
|
|
164
|
+
on: (event, listener) => {
|
|
165
|
+
emitter.on(event, listener);
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -720,7 +720,7 @@ export class OpencodeBridgeCore {
|
|
|
720
720
|
const model = index >= 0 ? models[index] : models.find((item) => `${item.providerId}/${item.modelId}` === normalized || item.modelId === normalized || storeModel(item.providerId, item.modelId) === normalized);
|
|
721
721
|
if (!model)
|
|
722
722
|
throw new Error(localize(locale, `未知模型:${raw}`, `Unknown model: ${raw}`));
|
|
723
|
-
this.store.
|
|
723
|
+
this.store.setChatModel(scopeId, storeModel(model.providerId, model.modelId));
|
|
724
724
|
const prefs = readPrefs(this.store.getChatSettings(scopeId));
|
|
725
725
|
if (prefs.variant && !model.variants.includes(prefs.variant))
|
|
726
726
|
this.writePrefs(scopeId, { ...prefs, variant: null });
|
|
@@ -1792,7 +1792,7 @@ export class OpencodeBridgeCore {
|
|
|
1792
1792
|
}
|
|
1793
1793
|
else {
|
|
1794
1794
|
const parsed = parseStoredModel(action.value);
|
|
1795
|
-
this.store.
|
|
1795
|
+
this.store.setChatModel(event.scopeId, action.value);
|
|
1796
1796
|
this.writePrefs(event.scopeId, { ...readPrefs(this.store.getChatSettings(event.scopeId)), variant: null });
|
|
1797
1797
|
answer = `${parsed.providerId}/${parsed.modelId}`;
|
|
1798
1798
|
}
|
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;
|
|
@@ -58,17 +59,50 @@ export declare class BridgeStore {
|
|
|
58
59
|
scopeId: string;
|
|
59
60
|
chatId: string;
|
|
60
61
|
} | null;
|
|
62
|
+
migrateTelegramUnnamespacedScope(botId: string, chatId: string): void;
|
|
61
63
|
getBinding(chatId: string): ThreadBinding | null;
|
|
62
64
|
setBinding(chatId: string, threadId: string, cwd: string | null): void;
|
|
63
65
|
listBindings(): ThreadBinding[];
|
|
64
66
|
clearBinding(chatId: string): void;
|
|
67
|
+
getWatchedThread(chatId: string): string | null;
|
|
68
|
+
setWatchedThread(chatId: string, threadId: string | null): void;
|
|
69
|
+
listWatchedThreads(): Array<{
|
|
70
|
+
scopeId: string;
|
|
71
|
+
threadId: string;
|
|
72
|
+
}>;
|
|
65
73
|
getChatSettings(chatId: string): ChatSessionSettings | null;
|
|
66
74
|
setChatSettings(chatId: string, model: string | null, reasoningEffort: ReasoningEffortValue | null, locale?: AppLocale | null): void;
|
|
75
|
+
setChatModel(chatId: string, model: string | null): void;
|
|
76
|
+
setChatEffort(chatId: string, effort: ReasoningEffortValue | null): void;
|
|
67
77
|
setChatLocale(chatId: string, locale: AppLocale): void;
|
|
68
78
|
setChatAccessPreset(chatId: string, accessPreset: AccessPresetValue | null): void;
|
|
69
79
|
setChatCollaborationMode(chatId: string, collaborationMode: CollaborationModeValue | null): void;
|
|
70
80
|
setChatServiceTier(chatId: string, serviceTier: string | null): void;
|
|
71
81
|
setChatActiveTurnMessageMode(chatId: string, activeTurnMessageMode: ActiveTurnMessageMode | null): void;
|
|
82
|
+
getActiveBackend(chatId: string): string | null;
|
|
83
|
+
setActiveBackend(chatId: string, backendId: string | null): void;
|
|
84
|
+
getScopeBackendBinding(scopeId: string, backendId: string): {
|
|
85
|
+
threadId: string;
|
|
86
|
+
cwd: string | null;
|
|
87
|
+
model?: string | null;
|
|
88
|
+
reasoningEffort?: string | null;
|
|
89
|
+
activeTurnMessageMode?: string | null;
|
|
90
|
+
serviceTier?: string | null;
|
|
91
|
+
accessPreset?: string | null;
|
|
92
|
+
} | null;
|
|
93
|
+
setScopeBackendBinding(scopeId: string, backendId: string, threadId: string, cwd: string | null, settings?: {
|
|
94
|
+
model?: string | null;
|
|
95
|
+
reasoningEffort?: string | null;
|
|
96
|
+
activeTurnMessageMode?: string | null;
|
|
97
|
+
serviceTier?: string | null;
|
|
98
|
+
accessPreset?: string | null;
|
|
99
|
+
} | null): void;
|
|
100
|
+
listScopeBackendBindings(scopeId: string): Array<{
|
|
101
|
+
backendId: string;
|
|
102
|
+
threadId: string;
|
|
103
|
+
cwd: string | null;
|
|
104
|
+
updatedAt: number;
|
|
105
|
+
}>;
|
|
72
106
|
findChatIdByThreadId(threadId: string): string | null;
|
|
73
107
|
findAllChatIdsByThreadId(threadId: string): string[];
|
|
74
108
|
countBindings(): number;
|
|
@@ -141,5 +175,15 @@ export declare class BridgeStore {
|
|
|
141
175
|
getCodexAuthPoolStats(): CodexAuthPoolStats;
|
|
142
176
|
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
177
|
listCodexAuthQuotaSnapshots(quotaIdentityIds: string[]): CodexAuthQuotaSnapshotRecord[];
|
|
178
|
+
recordTokenUsage(delta: TokenUsageDelta, backendId?: string): void;
|
|
179
|
+
setBackendCumulativeTokenUsage(usage: {
|
|
180
|
+
inputTokens: number;
|
|
181
|
+
outputTokens: number;
|
|
182
|
+
cachedTokens?: number;
|
|
183
|
+
totalTokens?: number;
|
|
184
|
+
turnsCount?: number;
|
|
185
|
+
}, backendId: string): void;
|
|
186
|
+
getCumulativeTokenUsage(backendId?: string): CumulativeTokenTotals;
|
|
187
|
+
getAllBackendTokenUsages(): CumulativeTokenUsageRecord[];
|
|
144
188
|
private ensureColumn;
|
|
145
189
|
}
|