File size: 9,110 Bytes
f7932bc
 
 
 
4407241
e7d4595
69ba4eb
b269533
9057700
cf06504
5232c15
0d13723
f7932bc
 
 
 
4407241
 
 
 
e7d4595
 
69ba4eb
 
5232c15
b269533
9057700
cf06504
 
5232c15
 
0d13723
f7932bc
 
 
 
 
 
 
4ed7180
f7932bc
 
 
 
 
4407241
 
 
 
 
 
 
 
 
f7932bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9057700
 
 
 
 
 
 
 
 
 
 
 
f7932bc
 
 
 
 
 
 
4407241
 
 
e7d4595
 
 
69ba4eb
 
 
b269533
 
 
cf06504
 
 
5232c15
 
0d13723
cf06504
 
 
 
 
 
 
b269533
 
 
5232c15
 
 
 
b269533
 
 
69ba4eb
 
 
5232c15
 
 
 
 
 
 
 
69ba4eb
 
 
e7d4595
 
 
 
4ed7180
 
 
 
 
 
 
 
4407241
 
 
 
 
 
 
f7932bc
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import http from 'node:http';
import { execFile } from 'node:child_process';
import { promises as fs } from 'node:fs';
import path from 'node:path';
import { ModelManager } from './model-manager.mjs';
import { CommunityStore } from '../community/store.mjs';
import { LspManager } from './lsp-manager.mjs';
import { DapManager } from './dap-manager.mjs';
import { WorkspaceManager } from './workspace-manager.mjs';
import { TrainingManager } from './training-manager.mjs';
import { ReplayStore } from './replay-store.mjs';
import { ArenaManager } from './arena-manager.mjs';

const HOST = '127.0.0.1';
const PORT = Number(process.env.AIDE_DAEMON_PORT || 4777);
const WORKSPACE = path.resolve(process.env.AIDE_WORKSPACE || process.cwd());
const MODEL_DIR = path.resolve(process.env.AIDE_MODEL_DIR || path.join(WORKSPACE, 'models'));
const MANIFEST = path.join(WORKSPACE, 'models', 'manifest.json');
const modelManager = new ModelManager({ manifestPath: MANIFEST, modelDir: MODEL_DIR, binaryPath: process.env.AIDE_LLAMA_SERVER || '/root/runtime/llama-b10333/llama-server' });
await modelManager.load().catch(() => {});
const communityStore = new CommunityStore(path.join(WORKSPACE, 'community', 'store.json'));
await communityStore.load().catch(() => {});
const lspManager = new LspManager({ manifestPath: path.join(WORKSPACE, 'languages', 'manifest.json'), workspace: WORKSPACE });
await lspManager.load().catch(() => {});
const dapManager = new DapManager({ manifestPath: path.join(WORKSPACE, 'debuggers', 'manifest.json'), workspace: WORKSPACE, pythonPath: process.env.AIDE_PYTHON || '' });
await dapManager.load().catch(() => {});
const workspaceManager = new WorkspaceManager(WORKSPACE);
const trainingManager = new TrainingManager({ manifestPath: path.join(WORKSPACE, 'training', 'manifest.json'), workspace: WORKSPACE });
await trainingManager.load().catch(() => {});
const replayStore = new ReplayStore(path.join(WORKSPACE, 'replays', 'store.json'));
await replayStore.load().catch(() => {});
const arenaManager = new ArenaManager({ modelManager, manifestPath: MANIFEST, suitePath: path.join(WORKSPACE, 'benchmarks', 'manifest.json') });

function json(response, status, body) {
  const payload = JSON.stringify(body);
  response.writeHead(status, {
    'Content-Type': 'application/json; charset=utf-8',
    'Content-Length': Buffer.byteLength(payload),
    'Access-Control-Allow-Origin': 'http://127.0.0.1:4173',
    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type'
  });
  response.end(payload);
}

async function body(request) {
  let data = '';
  for await (const chunk of request) {
    data += chunk;
    if (Buffer.byteLength(data) > 16 * 1024) throw new Error('request too large');
  }
  return data ? JSON.parse(data) : {};
}

function runGit(args) {
  return new Promise((resolve, reject) => {
    execFile('git', args, { cwd: WORKSPACE, timeout: 5000, maxBuffer: 256 * 1024 }, (error, stdout, stderr) => {
      if (error) reject(new Error(stderr.trim() || error.message));
      else resolve(stdout);
    });
  });
}

async function workspaceSummary() {
  const entries = await fs.readdir(WORKSPACE, { withFileTypes: true });
  return entries.filter(entry => !entry.name.startsWith('.')).slice(0, 200).map(entry => ({
    name: entry.name,
    kind: entry.isDirectory() ? 'directory' : 'file'
  }));
}

const server = http.createServer(async (request, response) => {
  if (request.method === 'OPTIONS') return json(response, 204, {});
  try {
    if (request.method === 'GET' && request.url === '/health') {
      return json(response, 200, { ok: true, service: 'aide-local-daemon', host: HOST, workspace: WORKSPACE });
    }
    if (request.method === 'GET' && request.url === '/api/workspace') {
      return json(response, 200, { workspace: WORKSPACE, entries: await workspaceSummary() });
    }
    if (request.method === 'GET' && request.url.startsWith('/api/file?')) {
      const relativePath = new URL(request.url, 'http://127.0.0.1').searchParams.get('path');
      return json(response, 200, { path: relativePath, content: await workspaceManager.read(relativePath) });
    }
    if (request.method === 'POST' && request.url === '/api/file/write') {
      const input = await body(request);
      return json(response, 200, await workspaceManager.write(input.path, input.content, input.approved));
    }
    if (request.method === 'POST' && request.url === '/api/patch/apply') {
      const input = await body(request);
      return json(response, 200, await workspaceManager.applyPatch(input.patch, input.approved));
    }
    if (request.method === 'GET' && request.url === '/api/git/status') {
      try {
        return json(response, 200, { workspace: WORKSPACE, status: await runGit(['status', '--short']) });
      } catch (error) {
        return json(response, 200, { workspace: WORKSPACE, status: '', unavailable: error.message });
      }
    }
    if (request.method === 'GET' && request.url === '/api/models/status') {
      return json(response, 200, { models: modelManager.status() });
    }
    if (request.method === 'GET' && request.url === '/api/community') {
      return json(response, 200, communityStore.list());
    }
    if (request.method === 'GET' && request.url === '/api/lsp/status') {
      return json(response, 200, { servers: lspManager.status() });
    }
    if (request.method === 'GET' && request.url === '/api/dap/status') {
      return json(response, 200, { adapters: dapManager.status() });
    }
    if (request.method === 'GET' && request.url === '/api/training/status') {
      return json(response, 200, trainingManager.status());
    }
    if (request.method === 'GET' && request.url === '/api/replays') return json(response, 200, replayStore.list());
    if (request.method === 'POST' && request.url === '/api/replays') return json(response, 201, { replay: await replayStore.add(await body(request)) });
    if (request.method === 'POST' && request.url === '/api/arena/run') return json(response, 200, await arenaManager.run((await body(request)).approved));
    if (request.method === 'POST' && request.url === '/api/training/start') {
      const input = await body(request);
      return json(response, 200, trainingManager.start(input.id, input.approved));
    }
    if (request.method === 'POST' && request.url === '/api/training/stop') {
      return json(response, 200, trainingManager.stop());
    }
    if (request.method === 'POST' && request.url === '/api/dap/start') {
      return json(response, 200, await dapManager.start((await body(request)).id));
    }
    if (request.method === 'POST' && request.url === '/api/dap/request') {
      const input = await body(request);
      return json(response, 200, await dapManager.request(input.id, input.request));
    }
    if (request.method === 'POST' && request.url === '/api/dap/stop') {
      return json(response, 200, await dapManager.stop((await body(request)).id));
    }
    if (request.method === 'POST' && request.url === '/api/lsp/start') {
      return json(response, 200, await lspManager.start((await body(request)).id));
    }
    if (request.method === 'POST' && request.url === '/api/lsp/request') {
      const input = await body(request);
      return json(response, 200, await lspManager.request(input.id, input.message));
    }
    if (request.method === 'POST' && request.url === '/api/lsp/notify') {
      const input = await body(request);
      return json(response, 200, lspManager.notify(input.id, input.message));
    }
    if (request.method === 'POST' && request.url === '/api/lsp/stop') {
      return json(response, 200, await lspManager.stop((await body(request)).id));
    }
    if (request.method === 'POST' && request.url === '/api/community/items') {
      const input = await body(request);
      return json(response, 201, { item: await communityStore.add(input.type, input.item) });
    }
    if (request.method === 'PUT' && request.url === '/api/community/items') {
      const input = await body(request);
      return json(response, 200, { item: await communityStore.update(input.type, input.index, input.item) });
    }
    if (request.method === 'DELETE' && request.url === '/api/community/items') {
      const input = await body(request);
      return json(response, 200, { item: await communityStore.remove(input.type, input.index) });
    }
    if (request.method === 'POST' && request.url === '/api/models/start') {
      return json(response, 200, await modelManager.start((await body(request)).id));
    }
    if (request.method === 'POST' && request.url === '/api/models/stop') {
      const id = (await body(request)).id;
      return json(response, 200, id ? await modelManager.stop(id) : (await modelManager.stopAll(), { status: 'stopped' }));
    }
    return json(response, 404, { error: 'not found' });
  } catch (error) {
    return json(response, 500, { error: 'local daemon error' });
  }
});

server.listen(PORT, HOST, () => {
  console.log(`AIDE local daemon listening on http://${HOST}:${PORT}`);
  console.log(`workspace: ${WORKSPACE}`);
});