Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12,215 changes: 0 additions & 12,215 deletions package-lock.json

This file was deleted.

8 changes: 7 additions & 1 deletion packages/codingcode/src/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,12 @@
const hooks = yield* HookService;
const mcp = yield* McpService;
const checkpoint = yield* CheckpointService;
const approval = yield* ApprovalService;

Check warning on line 131 in packages/codingcode/src/agent/agent.ts

View workflow job for this annotation

GitHub Actions / lint

'approval' is assigned a value but never used. Allowed unused vars must match /^_/u
const skills = yield* SkillService;
const runtime = yield* ProjectRuntimeService;
const todo = yield* TodoService;

Check warning on line 134 in packages/codingcode/src/agent/agent.ts

View workflow job for this annotation

GitHub Actions / lint

'todo' is assigned a value but never used. Allowed unused vars must match /^_/u
const rules = yield* RulesService;
const context = yield* ContextService;

Check warning on line 136 in packages/codingcode/src/agent/agent.ts

View workflow job for this annotation

GitHub Actions / lint

'context' is assigned a value but never used. Allowed unused vars must match /^_/u
const memory = yield* MemoryService;
const factory = yield* LLMFactoryService;

Expand Down Expand Up @@ -490,7 +490,13 @@
yield* q.offer({ _tag: 'ToolDenied', id: r.id, name: r.name, reason: r.reason });
} else {
const isOk = r.type === 'ok';
yield* q.offer({ _tag: 'ToolResult', id: r.id, name: r.name, output: resultOut, ok: isOk });
yield* q.offer({
_tag: 'ToolResult',
id: r.id,
name: r.name,
output: resultOut,
ok: isOk,
});
}
if (!messages.find((m) => m.tool_call_id === r.id)) {
const content =
Expand Down
2 changes: 1 addition & 1 deletion packages/codingcode/src/client/direct/sessions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Effect } from 'effect';
import { Effect } from 'effect';
import { SessionService } from '../../session/store.js';
import { WorkspaceService } from '../../core/workspace.js';
import { deleteSession } from '../../session/file-ops.js';
Expand Down
7 changes: 5 additions & 2 deletions packages/codingcode/src/memory/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import { updateMemoryEnabled } from '@codingcode/infra/config';
import { extractMemory } from './extractor.js';
import type { StructuredTranscript } from './types.js';

const MAX_BYTES = 16384;
const PROMPT_MAX_BYTES = 8192;

export class MemoryService extends Effect.Service<MemoryService>()('Memory', {
effect: Effect.gen(function* () {
const factory = yield* LLMFactoryService;
Expand All @@ -44,7 +47,7 @@ export class MemoryService extends Effect.Service<MemoryService>()('Memory', {
if (!projectAuto) return '';

const stripped = stripMarkersForPrompt(projectAuto);
const truncated = truncateForPrompt(stripped, cfg.promptMaxBytes);
const truncated = truncateForPrompt(stripped, PROMPT_MAX_BYTES);

return truncated ? `## Long-term Memory\n\n${truncated}` : '';
}
Expand Down Expand Up @@ -165,7 +168,7 @@ export class MemoryService extends Effect.Service<MemoryService>()('Memory', {
const projectContentFresh = readMemoryFile(projectPath);
const projectAutoFresh = extractAutoBlock(projectContentFresh);
const merged = mergeAutoBlocks(projectAutoFresh, extracted);
const truncated = enforceMaxBytes(merged, cfg.maxBytes);
const truncated = enforceMaxBytes(merged, MAX_BYTES);
const newProjectContent = replaceAutoBlock(projectContentFresh, truncated);

writeMemoryFileAtomic(projectPath, newProjectContent);
Expand Down
41 changes: 40 additions & 1 deletion packages/codingcode/src/server/routes/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ import {
updateMemoryExtraType as _updateMemoryExtraType,
deleteMemoryExtraType as _deleteMemoryExtraType,
} from '../../memory/config.js';
import {
loadConfig,
updateMaxSteps,
updateMaxStopContinuations,
updateContextCompactionModel,
updateMemoryModel,
} from '@codingcode/infra/config';
import { MemoryService } from '../../memory/index.js';
import { createRunWithLayer, errorResponse } from '../util.js';

Expand Down Expand Up @@ -268,7 +275,11 @@ export async function createSettingsRouter(rt: ManagedRt): Promise<Hono> {
// ---- Memory ----
settingsRouter.get('/memory/config', (c) => {
const cfg = getMemoryConfig();
return c.json({ enabled: cfg.enabled, types: getAllTypesWithStatus(cfg) });
return c.json({
enabled: cfg.enabled,
types: getAllTypesWithStatus(cfg),
model: cfg.model,
});
});

settingsRouter.post('/memory/enabled', async (c) => {
Expand Down Expand Up @@ -333,6 +344,34 @@ export async function createSettingsRouter(rt: ManagedRt): Promise<Hono> {
}
});

settingsRouter.post('/memory/model', async (c) => {
const body = (await c.req.json()) as { model: string };
updateMemoryModel(body.model);
return c.json({ model: body.model });
});

// ---- Agent config ----
settingsRouter.get('/agent/config', (c) => {
const cfg = loadConfig();
return c.json({ maxSteps: cfg.maxSteps, maxStopContinuations: cfg.maxStopContinuations });
});

settingsRouter.post('/agent/config', async (c) => {
const body = (await c.req.json()) as { maxSteps?: number; maxStopContinuations?: number };
if (body.maxSteps !== undefined) updateMaxSteps(body.maxSteps);
if (body.maxStopContinuations !== undefined)
updateMaxStopContinuations(body.maxStopContinuations);
const cfg = loadConfig();
return c.json({ maxSteps: cfg.maxSteps, maxStopContinuations: cfg.maxStopContinuations });
});

// ---- Context config ----
settingsRouter.post('/context/compaction-model', async (c) => {
const body = (await c.req.json()) as { compactionModel: string };
updateContextCompactionModel(body.compactionModel);
return c.json({ compactionModel: body.compactionModel });
});

// ---- Agents ----
settingsRouter.get('/agents', (c) => {
const rawCwd = c.req.query('cwd');
Expand Down
1 change: 0 additions & 1 deletion packages/codingcode/test/context/append-turn-end.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,4 @@ describe('appendTurnEnd', () => {
const parsed = JSON.parse(serialized);
expect(parsed.tokenCount).toBe(tokens);
});

});
2 changes: 1 addition & 1 deletion packages/codingcode/test/context/tokens.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect } from 'vitest';
import { describe, it, expect } from 'vitest';
import {
estimateTokensForContent,
estimateTokens,
Expand Down
2 changes: 1 addition & 1 deletion packages/codingcode/test/core/workspace.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { Effect } from 'effect';
import { mkdirSync, rmSync, writeFileSync } from 'fs';
import { join } from 'path';
Expand Down
2 changes: 0 additions & 2 deletions packages/codingcode/test/memory/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ function makeCfg(overrides?: Partial<MemoryConfig>): MemoryConfig {
return {
enabled: true,
model: '',
maxBytes: 16384,
promptMaxBytes: 8192,
extraTypes: [],
disabledTypes: [],
...overrides,
Expand Down
2 changes: 1 addition & 1 deletion packages/codingcode/test/self/todo/service.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect } from 'vitest';
import { describe, it, expect } from 'vitest';
import { Effect } from 'effect';
import { TodoService, countByStatus } from '../../../src/agent/todo.js';
import type { Todo } from '../../../src/agent/types.js';
Expand Down
2 changes: 1 addition & 1 deletion packages/codingcode/test/server/agent-routes.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect, vi } from 'vitest';
import { describe, it, expect, vi } from 'vitest';
import { Effect, Layer, ManagedRuntime } from 'effect';
import { createAgentRouter } from '../../src/server/routes/agent.js';
import { ApprovalService } from '../../src/approval/index.js';
Expand Down
2 changes: 1 addition & 1 deletion packages/codingcode/test/server/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect, vi } from 'vitest';
import { describe, it, expect, vi } from 'vitest';
import { Effect, Layer, ManagedRuntime } from 'effect';
import { createServer } from '../../src/server/index.js';
import { WorkspaceService } from '../../src/core/workspace.js';
Expand Down
103 changes: 102 additions & 1 deletion packages/codingcode/test/server/settings-routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,36 @@ import { SkillService } from '../../src/skills/service.js';
import { McpService } from '../../src/mcp/index.js';
import { WorkspaceService } from '../../src/core/workspace.js';

vi.mock('@codingcode/infra/config', () => ({
loadConfig: vi.fn().mockReturnValue({
maxSteps: 200,
maxStopContinuations: 2,
context: { compactionModel: '' },
memory: {
enabled: true,
model: '',
disabledTypes: [],
extraTypes: [],
},
activeModel: null,
server: { port: 8080 },
}),
updateMaxSteps: vi.fn(),
updateMaxStopContinuations: vi.fn(),
updateContextCompactionModel: vi.fn(),
updateMemoryModel: vi.fn(),
updateMemoryEnabled: vi.fn(),
updateMemoryDisabledTypes: vi.fn(),
updateMemoryExtraTypes: vi.fn(),
}));

vi.mock('../../src/memory/config.js', () => ({
getMemoryConfig: vi.fn().mockReturnValue({ enabled: true, disabledTypes: [], extraTypes: [] }),
getMemoryConfig: vi.fn().mockReturnValue({
enabled: true,
disabledTypes: [],
extraTypes: [],
model: '',
}),
getAllTypesWithStatus: vi
.fn()
.mockReturnValue([
Expand Down Expand Up @@ -613,3 +641,76 @@ describe('POST /skills', () => {
expect(setProjectSkillDisabledState).toHaveBeenCalledWith('/my-project', 'my-skill', true);
});
});

// ---- Memory config extended ----
describe('GET /memory/config (extended)', () => {
it('returns model field', async () => {
const res = await settingsRouter.request('/memory/config');
expect(res.status).toBe(200);
const body = await res.json();
expect(body).toHaveProperty('model');
});
});

// ---- Memory model ----
describe('POST /memory/model', () => {
it('updates memory model via updateMemoryModel', async () => {
const { updateMemoryModel } = await import('@codingcode/infra/config');
const res = await settingsRouter.request('/memory/model', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ model: 'deepseek-v4-flash' }),
});
expect(res.status).toBe(200);
expect(updateMemoryModel).toHaveBeenCalledWith('deepseek-v4-flash');
});
});

// ---- Agent config ----
describe('GET /agent/config', () => {
it('returns maxSteps and maxStopContinuations from loadConfig', async () => {
const res = await settingsRouter.request('/agent/config');
expect(res.status).toBe(200);
const body = await res.json();
expect(body).toHaveProperty('maxSteps');
expect(body).toHaveProperty('maxStopContinuations');
});
});

describe('POST /agent/config', () => {
it('updates maxSteps via updateMaxSteps', async () => {
const { updateMaxSteps } = await import('@codingcode/infra/config');
const res = await settingsRouter.request('/agent/config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ maxSteps: 500 }),
});
expect(res.status).toBe(200);
expect(updateMaxSteps).toHaveBeenCalledWith(500);
});

it('updates maxStopContinuations via updateMaxStopContinuations', async () => {
const { updateMaxStopContinuations } = await import('@codingcode/infra/config');
const res = await settingsRouter.request('/agent/config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ maxStopContinuations: 10 }),
});
expect(res.status).toBe(200);
expect(updateMaxStopContinuations).toHaveBeenCalledWith(10);
});
});

// ---- Context compaction model ----
describe('POST /context/compaction-model', () => {
it('updates compaction model via updateContextCompactionModel', async () => {
const { updateContextCompactionModel } = await import('@codingcode/infra/config');
const res = await settingsRouter.request('/context/compaction-model', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ compactionModel: 'gpt-4o-mini' }),
});
expect(res.status).toBe(200);
expect(updateContextCompactionModel).toHaveBeenCalledWith('gpt-4o-mini');
});
});
2 changes: 1 addition & 1 deletion packages/codingcode/test/server/util.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect } from 'vitest';
import { describe, it, expect } from 'vitest';
import { errorResponse } from '../../src/server/util.js';
import { AgentError } from '../../src/core/error.js';

Expand Down
2 changes: 1 addition & 1 deletion packages/codingcode/test/session/delete-message.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect } from 'vitest';
import { describe, it, expect } from 'vitest';
import { mkdirSync, writeFileSync, readFileSync, rmSync, existsSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
Expand Down
2 changes: 1 addition & 1 deletion packages/codingcode/test/session/rollback.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect } from 'vitest';
import { describe, it, expect } from 'vitest';
import { mkdirSync, writeFileSync, readFileSync, rmSync, existsSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect } from 'vitest';
import { describe, it, expect } from 'vitest';
import { mkdirSync, writeFileSync, appendFileSync, rmSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
Expand Down
2 changes: 1 addition & 1 deletion packages/codingcode/test/session/usage-persist.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect } from 'vitest';
import { describe, it, expect } from 'vitest';
import { mkdirSync, writeFileSync, readFileSync, rmSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
Expand Down
45 changes: 43 additions & 2 deletions packages/desktop/src/lib/core-api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { API_BASE } from './api';
import { API_BASE, api } from './api';
import { createHttpClients, type AgentRuntimeClient } from '@codingcode/core/client/http-clients';

const clients = createHttpClients(API_BASE);
Expand Down Expand Up @@ -64,8 +64,9 @@ export function sendApprovalResponse(
export function getMemoryConfig(): Promise<{
enabled: boolean;
types: Array<{ name: string; description: string; isBuiltIn: boolean; disabled: boolean }>;
model: string;
}> {
return clients.settings.getMemoryConfig();
return api('/api/settings/memory/config');
}

export function setMemoryEnabled(enabled: boolean): Promise<void> {
Expand All @@ -91,6 +92,46 @@ export function deleteMemoryExtraType(name: string): Promise<void> {
return clients.settings.deleteMemoryExtraType(name);
}

export function setMemoryModel(model: string): Promise<{ model: string }> {
return api('/api/settings/memory/model', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ model }),
});
}

// ---- Settings: Agent config ----

export async function getAgentConfig(): Promise<{
maxSteps: number;
maxStopContinuations: number;
}> {
return api('/api/settings/agent/config');
}

export async function setAgentConfig(partial: {
maxSteps?: number;
maxStopContinuations?: number;
}): Promise<{ maxSteps: number; maxStopContinuations: number }> {
return api('/api/settings/agent/config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(partial),
});
}

// ---- Settings: Context config ----

export async function setCompactionModel(
compactionModel: string
): Promise<{ compactionModel: string }> {
return api('/api/settings/context/compaction-model', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ compactionModel }),
});
}

// ---- Settings: MCP ----

export function listMcpServers(_cwd?: string): Promise<any[]> {
Expand Down
Loading
Loading