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
7 changes: 5 additions & 2 deletions packages/codingcode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@
"./server/adapter": "./src/server/adapter.ts",
"./server/port-discovery": "./src/server/port-discovery.ts",
"./client/types": "./src/client/types.ts",
"./client/direct": "./src/client/direct.ts",
"./client/http": "./src/client/http.ts",
"./client/http-clients": "./src/client/http/index.ts",
"./client/direct-clients": "./src/client/direct/index.ts",
"./direct/agent-runtime": "./src/direct/agent-runtime.ts",
"./direct/sessions": "./src/direct/sessions.ts",
"./direct/settings": "./src/direct/settings.ts",
"./direct/models": "./src/direct/models.ts",
"./agent/stream-adapter": "./src/agent/stream-adapter.ts",
"./checkpoint/checkpoint-service": "./src/checkpoint/checkpoint-service.ts",
"./checkpoint/shadow-git": "./src/checkpoint/shadow-git.ts",
"./checkpoint/bootstrap": "./src/checkpoint/bootstrap.ts",
Expand Down
32 changes: 14 additions & 18 deletions packages/codingcode/src/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import { MemoryService } from '../memory/index.js';
import { createLogger } from '@codingcode/infra/logger';
import { resolveSubagentEnabled, resolveAgentDisabled } from '../subagent/registry.js';
import { ProjectRuntimeService, modeToProfile } from '../runtime/project-runtime.js';

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

View workflow job for this annotation

GitHub Actions / lint

'modeToProfile' is defined but never used. Allowed unused vars must match /^_/u
import { createDispatchAgentTool } from '../tools/domains/subagent/dispatch.js';
import { LLMFactoryService } from '../llm/factory.js';
import { getBuiltinTools } from '../tools/providers.js';
Expand Down Expand Up @@ -122,10 +122,10 @@
llm: LLMClient,
options: {
signal?: AbortSignal;
approvalOverride?: any;
mode: SessionMode;
permissionMode: PermissionMode;
model: string;
approvalOverride?: import('../approval/index.js').ApprovalService;
mode?: SessionMode;
permissionMode?: PermissionMode;
model?: string;
}
) =>
Effect.gen(function* () {
Expand All @@ -134,12 +134,12 @@
const hooks = yield* HookService;
const mcp = yield* McpService;
const checkpoint = yield* CheckpointService;
const approval = yield* ApprovalService;

Check warning on line 137 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 140 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 142 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 All @@ -148,18 +148,19 @@
yield* skills.evictProject(normalizedCwd);

if (!sessionId) {
const created = yield* session.create(normalizedCwd, {
if (!options.mode || !options.permissionMode || !options.model) {
return yield* Effect.fail(
new AgentError(
'CONFIG_MISSING',
'new session requires mode, permissionMode, and model'
)
);
}
const created = yield* session.createSessionWithProfile(normalizedCwd, {
model: options.model,
mode: options.mode,
permissionMode: options.permissionMode,
});
const profile = modeToProfile(options.mode);
yield* runtime.setSessionProfile(
normalizedCwd,
created.sessionId,
profile,
options.permissionMode
);
sessionId = created.sessionId;
}
const state = yield* session.load(normalizedCwd, sessionId);
Expand Down Expand Up @@ -335,12 +336,7 @@

const compressResult = yield* Effect.tryPromise({
try: () =>
context.compactIfNeeded(
state.transcriptPath,
messages,
llm.modelInfo.maxTokens,
llm
),
context.compactIfNeeded(state.transcriptPath, messages, llm.modelInfo.maxTokens, llm),
catch: (e) => new AgentError('LLM_FAILED', String(e)),
});
if (compressResult.didCompress && compressResult.messages) {
Expand Down Expand Up @@ -499,7 +495,7 @@
}
}

const record = yield* session.recordAssistant(state, resp.content, toolCalls!, resp.usage);

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

View workflow job for this annotation

GitHub Actions / lint

'record' is assigned a value but never used. Allowed unused vars must match /^_/u
const allResults = yield* executor.executeBatch(toolCalls, state.sessionId, {
turnId: state.currentTurnId,
projectPath,
Expand Down
67 changes: 67 additions & 0 deletions packages/codingcode/src/agent/stream-adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import type { AgentEvent } from './types.js';
import type { StreamChunk } from '../client/types.js';

export async function* agentEventToStreamChunk(
source: AsyncGenerator<AgentEvent, any, unknown>
): AsyncGenerator<StreamChunk, void, unknown> {
let currentStep = 0;
for await (const event of source) {
switch (event._tag) {
case 'Step':
currentStep = event.step;
break;
case 'TurnId':
yield { type: 'turn_id', turnId: event.turnId };
break;
case 'LlmChunk':
yield { type: 'text', text: event.text, messageId: currentStep };
break;
case 'Assistant':
yield { type: 'message', id: currentStep, content: event.content, partial: false };
break;
case 'ToolStart':
yield { type: 'tool_start', id: event.id, name: event.name, args: event.args };
break;
case 'ToolResult':
yield {
type: 'tool_result',
id: event.id,
name: event.name,
output: event.output,
ok: event.ok,
};
break;
case 'ToolDenied':
yield { type: 'tool_denied', id: event.id, name: event.name, reason: event.reason };
break;
case 'Error':
yield {
type: 'error',
message: event.error.message ?? String(event.error),
code: event.error.code,
};
break;
case 'Done':
yield { type: 'done' };
break;
case 'TodoUpdate':
yield { type: 'todo_update', items: event.items as any };
break;
case 'Usage':
yield {
type: 'usage',
prompt: event.prompt,
completion: event.completion,
total: event.total,
};
break;
case 'ReactiveCompact':
yield {
type: 'reactive_compact',
released: event.released,
promptEstimate: event.promptEstimate,
};
break;
}
}
}
2 changes: 1 addition & 1 deletion packages/codingcode/src/agent/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,6 @@ export interface RunStreamOptions {
agentName?: string;
maxStepsOverride?: number;
maxStopContinuations?: number;
approvalOverride?: any;
approvalOverride?: import('../approval/index.js').ApprovalService;
rulesText?: string;
}
15 changes: 8 additions & 7 deletions packages/codingcode/src/approval/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export class ApprovalService extends Effect.Service<ApprovalService>()('Approval
const ruleEngine: RuleEngine = createRuleEngine(DEFAULT_DENY_RULES);
const destructiveTools = new Set(DANGEROUS_TOOL_NAMES);
const readonlyTools = new Set(READONLY_TOOL_NAMES);
let _globalPermissionMode: PermissionMode = 'default';

function makeForkedService(
engine: RuleEngine,
Expand Down Expand Up @@ -64,6 +63,7 @@ export class ApprovalService extends Effect.Service<ApprovalService>()('Approval
fork: (opts?: {
extraDenyRules?: PermissionRule[];
readonly?: boolean;
permissionMode?: PermissionMode;
}): Effect.Effect<ApprovalService> =>
Effect.sync(() => {
const nextEngine = createRuleEngine(engine.getAllRules());
Expand All @@ -84,7 +84,7 @@ export class ApprovalService extends Effect.Service<ApprovalService>()('Approval
}
return makeForkedService(
nextEngine,
currentPermMode,
opts?.permissionMode ?? currentPermMode,
new Set(roTools),
new Set(destTools)
);
Expand Down Expand Up @@ -112,7 +112,7 @@ export class ApprovalService extends Effect.Service<ApprovalService>()('Approval
ruleEngine,
readonlyTools,
destructiveTools,
permissionMode: _globalPermissionMode,
permissionMode: 'default',
onAlways: (rule) => ruleEngine.addRule(rule),
onNever: (rule) => ruleEngine.addRule(rule),
sessionId: request.sessionId,
Expand All @@ -129,16 +129,17 @@ export class ApprovalService extends Effect.Service<ApprovalService>()('Approval

removeRule: (id: string): Effect.Effect<void> => Effect.sync(() => ruleEngine.removeRule(id)),

setPermissionMode: (mode: PermissionMode): Effect.Effect<void> =>
setPermissionMode: (_mode: PermissionMode): Effect.Effect<void> =>
Effect.sync(() => {
_globalPermissionMode = mode;
/* no-op at root; only fork children maintain their own currentPermMode */
}),

getPermissionMode: (): PermissionMode => _globalPermissionMode,
getPermissionMode: (): PermissionMode => 'default',

fork: (opts?: {
extraDenyRules?: PermissionRule[];
readonly?: boolean;
permissionMode?: PermissionMode;
}): Effect.Effect<ApprovalService> =>
Effect.sync(() => {
const parentRules = ruleEngine.getAllRules();
Expand All @@ -161,7 +162,7 @@ export class ApprovalService extends Effect.Service<ApprovalService>()('Approval
}
return makeForkedService(
childEngine,
_globalPermissionMode,
opts?.permissionMode ?? 'default',
new Set(readonlyTools),
new Set(destructiveTools)
);
Expand Down
6 changes: 5 additions & 1 deletion packages/codingcode/src/approval/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
export type PermissionMode = 'default' | 'acceptEdits' | 'bypass';

export const PERMISSION_MODES: readonly PermissionMode[] = ['default', 'acceptEdits', 'bypass'] as const;
export const PERMISSION_MODES: readonly PermissionMode[] = [
'default',
'acceptEdits',
'bypass',
] as const;

export function isPermissionMode(value: unknown): value is PermissionMode {
return typeof value === 'string' && (PERMISSION_MODES as readonly string[]).includes(value);
Expand Down
14 changes: 10 additions & 4 deletions packages/codingcode/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,12 @@ async function main() {

if (tuiOnly) {
const tuiPath = '../../tui/src/index.js';
const { runTui } = yield* Effect.tryPromise(() => import(tuiPath));
const { runTui, createTuiClientFromFacades } = yield* Effect.tryPromise(() =>
import(tuiPath)
);
const llm = yield* llmFactory.getLLMClient();
runTui({ llm, rt });
const client = createTuiClientFromFacades(llm, rt);
runTui({ client });
return;
}

Expand All @@ -50,9 +53,12 @@ async function main() {

if (!serveOnly) {
const tuiPath = '../../tui/src/index.js';
const { runTui } = yield* Effect.tryPromise(() => import(tuiPath));
const { runTui, createTuiClientFromFacades } = yield* Effect.tryPromise(() =>
import(tuiPath)
);
const llm = yield* llmFactory.getLLMClient();
runTui({ llm, rt });
const client = createTuiClientFromFacades(llm, rt);
runTui({ client });
}
});

Expand Down
Loading
Loading