Skip to content
Merged

Dev #10

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
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ out
.remix-serve-node_modules
.env/*
.agent-sessions/
.pnpm-store/
packages/client/dist/
*.tsbuildinfo
bundle.*
docs/*
pnpm-workspace.yaml
559 changes: 559 additions & 0 deletions bun.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions bunfig.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[install]
linker = "hoisted"
20 changes: 12 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
"version": "0.1.0",
"private": true,
"type": "module",
"packageManager": "bun@1.3.11",
"workspaces": [
"packages/*"
],
"scripts": {
"dev": "tsx source/app.tsx",
"start": "tsx source/app.tsx",
Expand All @@ -11,31 +15,31 @@
"test": "vitest run --reporter verbose",
"build:agent-core": "tsc -p packages/agent-core/tsconfig.json",
"export:web": "tsx source/export-web.ts",
"dev:client": "vite --config packages/client/vite.config.ts",
"build:client": "vite build --config packages/client/vite.config.ts",
"preview:client": "vite preview --config packages/client/vite.config.ts"
"dev:client": "bun run --cwd packages/client dev",
"build:client": "bun run --cwd packages/client build",
"preview:client": "bun run --cwd packages/client preview"
},
"dependencies": {
"dotenv": "^17.4.2",
"ink": "^7.1.1",
"ink-spinner": "^5.0.0",
"ink-text-input": "^6.0.0",
"openai": "^6.34.0",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"tiktoken": "^1.0.20"
},
"devDependencies": {
"@tailwindcss/vite": "^4.3.3",
"@types/node": "^25.6.0",
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.4",
"@vitejs/plugin-react": "^6.0.5",
"prettier": "^3.4.2",
"tailwindcss": "^4.3.3",
"tsx": "^4.23.7",
"typescript": "^6.0.3",
"vite": "^8.2.0",
"vitest": "^3.2.4"
}
},
"trustedDependencies": [
"esbuild",
"tesseract.js"
]
}
21 changes: 21 additions & 0 deletions packages/agent-core/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "@call-code/agent-core",
"version": "0.1.0",
"private": true,
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc -p tsconfig.json --noEmit"
},
"dependencies": {
"dotenv": "^17.4.2",
"openai": "^6.34.0",
"tesseract.js": "^7.0.0",
"tiktoken": "^1.0.20"
},
"devDependencies": {
"typescript": "^6.0.3"
}
}
7 changes: 0 additions & 7 deletions packages/agent-core/src/context/builder.ts

This file was deleted.

7 changes: 7 additions & 0 deletions packages/agent-core/src/harness/context/builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export { ContextBuilder } from '@agent-core/harness/context/context-builder';
export type {
ContextMessage,
MessageRole,
RuntimeContext,
} from '@agent-core/harness/context/context-types';
export { buildRuntimeContext } from '@agent-core/harness/context/runtime-context';
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { get_encoding, type Tiktoken } from 'tiktoken';
import type { ContextMessage } from '@agent-core/context/context-types';
import type { ContextMessage } from '@agent-core/harness/context/context-types';

export class ContextBuilder {
private readonly encoder: Tiktoken;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ContextMessage } from '@agent-core/context/context-types';
import type { ContextMessage } from '@agent-core/harness/context/context-types';

export interface HistorySummary {
summary: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { memoryStore } from '@agent-core/memory/memory-store';
import { memoryStore } from '@agent-core/harness/context/memory/memory-store';

export interface RetrievedMemory {
longFacts: string[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { randomUUID } from 'node:crypto';
import type {
LongMemoryItem,
MemorySnapshot,
} from '@agent-core/memory/memory-schema';
} from '@agent-core/harness/context/memory/memory-schema';

export class MemoryStore {
private readonly longMemory: LongMemoryItem[] = [];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { TaskState } from '@core/state';
import type { ContextMessage } from '@agent-core/context/context-types';
import { memoryStore } from '@agent-core/memory/memory-store';
import type { ContextMessage } from '@agent-core/harness/context/context-types';
import { memoryStore } from '@agent-core/harness/context/memory/memory-store';

const countStableMentions = (messages: ContextMessage[], text: string): number =>
messages.reduce((count, item) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { TaskState } from '@core/state';
import { createTaskContext } from '@agent-core/context/task-context';
import { summarizeHistory } from '@agent-core/context/context-summarizer';
import { ContextBuilder } from '@agent-core/context/context-builder';
import type { TaskState } from '@agent-core/harness/core/state';
import { createTaskContext } from '@agent-core/harness/context/task-context';
import { summarizeHistory } from '@agent-core/harness/context/context-summarizer';
import { ContextBuilder } from '@agent-core/harness/context/context-builder';
import type {
ContextMessage,
RuntimeContext,
} from '@agent-core/context/context-types';
} from '@agent-core/harness/context/context-types';

export interface BuildRuntimeContextInput {
system: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TaskState } from '@core/state';
import type { TaskState } from '@agent-core/harness/core/state';

export interface TaskContext {
id: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { runLoop } from '@core/loop';
import type { StreamHandlers } from '@core/llm';
import { createTaskState, type AgentMode } from '@core/state';
import { runLoop } from '@agent-core/harness/core/loop';
import type { StreamHandlers } from '@agent-core/harness/core/llm';
import { createTaskState, type AgentMode } from '@agent-core/harness/core/state';

export interface AgentOptions {
mode?: AgentMode;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import { streamLLM } from '@core/llm';
import { ContextBuilder } from '@agent-core/context/context-builder';
import { buildRuntimeContext } from '@agent-core/context/runtime-context';
import type { ContextMessage } from '@agent-core/context/context-types';
import { systemPrompt } from '@prompt/system';
import { toolPrompt } from '@prompt/tool';
import { getModePrompt } from '@prompt/modes';
import type { StreamHandlers } from '@core/llm';
import type { TaskState } from '@core/state';
import { streamLLM } from '@agent-core/harness/core/llm';
import { ContextBuilder } from '@agent-core/harness/context/context-builder';
import { buildRuntimeContext } from '@agent-core/harness/context/runtime-context';
import type { ContextMessage } from '@agent-core/harness/context/context-types';
import { systemPrompt } from '@agent-core/harness/prompt/system';
import { toolPrompt } from '@agent-core/harness/prompt/tool';
import { getModePrompt } from '@agent-core/harness/prompt/modes';
import type { StreamHandlers } from '@agent-core/harness/core/llm';
import type { TaskState } from '@agent-core/harness/core/state';
import {
extractFinalText,
parseAgentResponse,
shouldContinueLoop,
} from '@protocol/parser';
import { isToolCallAction } from '@protocol/action';
import { executeToolCall } from '@tools/executor';
import { promoteStableFact } from '@agent-core/memory/memory-writer';
import { retrieveMemoryForTask } from '@agent-core/memory/memory-retriever';
} from '@agent-core/harness/protocol/parser';
import { isToolCallAction } from '@agent-core/harness/protocol/action';
import { executeToolCall } from '@agent-core/harness/tools/executor';
import { promoteStableFact } from '@agent-core/harness/context/memory/memory-writer';
import { retrieveMemoryForTask } from '@agent-core/harness/context/memory/memory-retriever';
import {
appendTaskEntry,
appendTaskRecord,
ensureTaskSession,
getSharedSessionStoreOrNull,
readTaskHistory,
type SessionStoreLike,
} from '@agent-core/session/session-repository';
} from '@agent-core/harness/session/session-repository';

const contextBuilder = new ContextBuilder(8000);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { AgentMode } from '@core/state';
import { modePolicies } from '@policy/modes';
import type { AgentMode } from '@agent-core/harness/core/state';
import { modePolicies } from '@agent-core/harness/policy/modes';

const toolPermissionByName = (toolName: string, mode: AgentMode): boolean => {
const policy = modePolicies[mode];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AgentMode } from '@core/state';
import type { AgentMode } from '@agent-core/harness/core/state';

export interface ModePolicy {
readonly allowRunCommand: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AgentMode } from '@core/state';
import type { AgentMode } from '@agent-core/harness/core/state';

const modeSystemPrompts: Record<AgentMode, string> = {
plan: `
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const toolPrompt = `
可用工具仅有以下 5 个:
可用工具仅有以下 6 个:

1. get_environment()
- 返回 cwd、home、desktop、documents、downloads、temp
Expand All @@ -22,6 +22,11 @@ export const toolPrompt = `
- 查看目录结构
- path 支持:绝对路径、相对路径、~/...、Desktop/...、桌面/...、desktop:/...

6. ocr_image(path: string, lang?: string)
- 识别图片中的文字,返回识别文本和置信度
- path 支持:绝对路径、相对路径、~/...、Desktop/...、桌面/...、desktop:/...
- lang 可选,默认 eng;中文可传 chi_sim+eng

约束:
- 禁止调用未列出的工具。
- 工具参数必须完整且类型正确。
Expand Down
5 changes: 5 additions & 0 deletions packages/agent-core/src/harness/protocol/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type { ToolCallAction, FinalAction, AgentAction } from '@agent-core/harness/protocol/action';
export { isToolCallAction, isFinalAction, isAgentAction } from '@agent-core/harness/protocol/action';
export type { ToolResultObservation } from '@agent-core/harness/protocol/observation';
export { createToolResultObservation } from '@agent-core/harness/protocol/observation';
export { parseAgentResponse, shouldContinueLoop, extractFinalText } from '@agent-core/harness/protocol/parser';
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isAgentAction, isFinalAction, isToolCallAction, type AgentAction } from '@protocol/action';
import { isAgentAction, isFinalAction, isToolCallAction, type AgentAction } from '@agent-core/harness/protocol/action';

export const parseAgentResponse = (response: string): AgentAction | null => {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { TaskState } from '@core/state';
import type { ContextMessage } from '@agent-core/context/context-types';
import type { TaskState } from '@agent-core/harness/core/state';
import type { ContextMessage } from '@agent-core/harness/context/context-types';

/** 默认泳道名称,与 session-sqlite store 保持一致 */
export const DEFAULT_LANE = 'default';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { tools } from '@tools';
import { enforceToolPermission } from '@policy/guard';
import type { AgentMode } from '@core/state';
import type { ToolCallAction } from '@protocol/action';
import { createToolResultObservation } from '@protocol/observation';
import { tools } from '@agent-core/harness/tools';
import { enforceToolPermission } from '@agent-core/harness/policy/guard';
import type { AgentMode } from '@agent-core/harness/core/state';
import type { ToolCallAction } from '@agent-core/harness/protocol/action';
import { createToolResultObservation } from '@agent-core/harness/protocol/observation';

export interface ToolExecutionResult {
content: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { access } from 'node:fs/promises';
import process from 'node:process';
import { getKnownLocations } from '@tools/pathUtils';
import { getKnownLocations } from '@agent-core/harness/tools/pathUtils';

const exists = async (path: string) => {
try {
Expand Down
19 changes: 19 additions & 0 deletions packages/agent-core/src/harness/tools/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { getEnvironmentTool } from '@agent-core/harness/tools/getEnvironment';
import { listFilesTool } from '@agent-core/harness/tools/listFiles';
import { readFileTool } from '@agent-core/harness/tools/readFile';
import { runCommandTool } from '@agent-core/harness/tools/runCommand';
import { writeFileTool } from '@agent-core/harness/tools/writeFile';
export {
getEnvironmentTool,
listFilesTool,
readFileTool,
runCommandTool,
writeFileTool,
};
export const tools = [
getEnvironmentTool,
listFilesTool,
readFileTool,
runCommandTool,
writeFileTool,
];
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { readdir } from 'node:fs/promises';
import pathModule from 'node:path';
import { resolveUserPath } from '@tools/pathUtils';
import { resolveUserPath } from '@agent-core/harness/tools/pathUtils';

export const listFilesTool = {
name: 'list_files',
Expand Down
53 changes: 53 additions & 0 deletions packages/agent-core/src/harness/tools/ocr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { readFile } from 'node:fs/promises';
import Tesseract from 'tesseract.js';
import { resolveUserPath } from '@tools/pathUtils';

const DEFAULT_LANG = 'eng';

export const ocrImageTool = {
name: 'ocr_image',
description: 'Recognize text from an image file using Tesseract OCR',
parameters: {
type: 'object',
properties: {
path: {
type: 'string',
description: 'The path to the image file to recognize',
},
lang: {
type: 'string',
description:
'Optional Tesseract language code, e.g. eng or chi_sim+eng',
},
},
required: ['path'],
},
run: async (input: any) => {
const { path, lang } = input;
if (!path || typeof path !== 'string') {
throw new Error('Invalid path');
}

const language =
typeof lang === 'string' && lang.trim() ? lang.trim() : DEFAULT_LANG;
const resolvedPath = resolveUserPath(path);
const image = await readFile(resolvedPath);

const worker = await Tesseract.createWorker(language, undefined, {
logger: () => {},
});

try {
const { data } = await worker.recognize(image);
return {
requestedPath: path,
path: resolvedPath,
language,
text: data.text,
confidence: data.confidence,
};
} finally {
await worker.terminate();
}
},
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { readFile } from 'node:fs/promises';
import { resolveUserPath } from '@tools/pathUtils';
import { resolveUserPath } from '@agent-core/harness/tools/pathUtils';

export const readFileTool = {
name: 'read_file',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { exec } from 'node:child_process';
import { promisify } from 'node:util';
import { resolveUserPath } from '@tools/pathUtils';
import { resolveUserPath } from '@agent-core/harness/tools/pathUtils';

const execAsync = promisify(exec);

Expand Down
Loading
Loading