feat(theta): implement θ-cycle for autonomous processing

- Add 6-phase processing cycle: OBSERVE → ANALYZE → DECIDE → EXECUTE → VERIFY → IMPROVE
- Types and interfaces in types.ts
- Each phase has dedicated module
- Entry point in index.ts

Closes #1801
This commit is contained in:
Shunsuke Hayashi 2026-01-25 22:17:32 +09:00
parent afb659487c
commit 76e87167c9
8 changed files with 1779 additions and 0 deletions

202
src/theta/analyze.ts Normal file
View File

@ -0,0 +1,202 @@
/**
* θ ANALYZE: 意図解析
*
*
*/
import { emitAgentEvent } from "../infra/agent-events.js";
import {
type AnalysisResult,
ThetaCycleState,
ThetaEvent,
ThetaEventType,
ThetaPhase,
} from "./types.js";
// 型のエクスポート
export type { AnalysisResult };
/**
*
*
* @param state - θ
* @returns
*/
export async function analyze(
state: ThetaCycleState,
): Promise<{ state: ThetaCycleState; result: AnalysisResult }> {
const { runId } = state;
// フェーズ開始イベント
emitPhaseEvent(runId, ThetaEventType.PHASE_START, {
phase: ThetaPhase.ANALYZE,
});
try {
// 入力データの取得
const input = state.context.get("observe.input");
const metadata = state.context.get("observe.metadata") as Record<string, unknown> | undefined;
// 意図解析
const intent = extractIntent(input);
const entities = extractEntities(input);
const context = buildContext(input, metadata);
const confidence = calculateConfidence(intent, entities);
const result: AnalysisResult = {
intent,
entities,
context,
confidence,
};
// 分析イベント記録
const analysisEvent: ThetaEvent = {
runId,
phase: ThetaPhase.ANALYZE,
timestamp: Date.now(),
type: ThetaEventType.ANALYSIS,
data: {
result,
},
};
state.events.push(analysisEvent);
state.currentPhase = ThetaPhase.ANALYZE;
state.context.set("analyze.result", result);
// Agentイベントを発行
emitAgentEvent({
runId,
stream: "tool",
data: {
type: "analyze",
intent,
entities,
confidence,
},
});
// フェーズ完了イベント
emitPhaseEvent(runId, ThetaEventType.PHASE_COMPLETE, {
phase: ThetaPhase.ANALYZE,
intent,
confidence,
});
return { state, result };
} catch (error) {
// エラーイベント
emitPhaseEvent(runId, ThetaEventType.PHASE_ERROR, {
phase: ThetaPhase.ANALYZE,
error: error instanceof Error ? error.message : String(error),
});
throw error;
}
}
/**
*
*/
function extractIntent(input: unknown): string {
if (typeof input === "string") {
// 簡易的な意図抽出実際はLLM等を使用
const lowerInput = input.toLowerCase();
if (lowerInput.includes("create") || lowerInput.includes("new")) {
return "create";
}
if (lowerInput.includes("delete") || lowerInput.includes("remove")) {
return "delete";
}
if (lowerInput.includes("update") || lowerInput.includes("modify")) {
return "update";
}
if (lowerInput.includes("search") || lowerInput.includes("find")) {
return "search";
}
return "unknown";
}
if (typeof input === "object" && input !== null) {
const obj = input as Record<string, unknown>;
if (typeof obj.intent === "string") {
return obj.intent;
}
}
return "unknown";
}
/**
*
*/
function extractEntities(input: unknown): Record<string, unknown> {
const entities: Record<string, unknown> = {};
if (typeof input === "object" && input !== null) {
const obj = input as Record<string, unknown>;
// よく使われるエンティティキーを抽出
const entityKeys = ["name", "id", "type", "value", "target", "source"];
for (const key of entityKeys) {
if (key in obj) {
entities[key] = obj[key];
}
}
}
return entities;
}
/**
*
*/
function buildContext(input: unknown, metadata?: Record<string, unknown>): Record<string, unknown> {
return {
inputType: typeof input,
hasMetadata: metadata !== undefined,
metadataKeys: metadata ? Object.keys(metadata) : [],
timestamp: Date.now(),
};
}
/**
*
*/
function calculateConfidence(intent: string, entities: Record<string, unknown>): number {
let score = 0.5; // 基本スコア
// 意図が特定できている
if (intent !== "unknown") {
score += 0.2;
}
// エンティティが抽出できている
if (Object.keys(entities).length > 0) {
score += 0.1 * Math.min(Object.keys(entities).length, 3);
}
return Math.min(score, 1.0);
}
/**
*
*
* @param state - θ
* @returns
*/
export function getAnalysisResult(state: ThetaCycleState): AnalysisResult | undefined {
return state.context.get("analyze.result") as AnalysisResult | undefined;
}
/**
*
*/
function emitPhaseEvent(runId: string, type: ThetaEventType, data: Record<string, unknown>): void {
emitAgentEvent({
runId,
stream: "tool",
data: {
type: "theta_event",
thetaEventType: type,
...data,
},
});
}

238
src/theta/decide.ts Normal file
View File

@ -0,0 +1,238 @@
/**
* θ DECIDE: 処理方針決定Agent選択
*
*
*/
import { emitAgentEvent } from "../infra/agent-events.js";
import {
type AnalysisResult,
ThetaCycleState,
ThetaEvent,
ThetaEventType,
ThetaPhase,
} from "./types.js";
import type { DecisionResult } from "./types.js";
// 型のエクスポート
export type { DecisionResult };
/**
*
*/
interface AgentDefinition {
/** エージェントID */
id: string;
/** 対応する意図 */
intents: string[];
/** キャパシティ */
capacity: number;
}
/** 利用可能なエージェント一覧 */
const AVAILABLE_AGENTS: AgentDefinition[] = [
{ id: "conductor", intents: ["*"], capacity: 10 },
{ id: "codegen", intents: ["create", "update"], capacity: 5 },
{ id: "review", intents: ["verify", "check"], capacity: 3 },
{ id: "deploy", intents: ["deploy", "release"], capacity: 2 },
];
/**
*
*/
interface StrategyDefinition {
/** 戦略ID */
id: string;
/** 対応する意図 */
intents: string[];
/** 推奨エージェント */
defaultAgent: string;
/** 推定実行時間(ms) */
estimatedDuration: number;
}
/** 利用可能な処理方針一覧 */
const AVAILABLE_STRATEGIES: StrategyDefinition[] = [
{
id: "direct_execution",
intents: ["create", "update", "delete"],
defaultAgent: "codegen",
estimatedDuration: 5000,
},
{
id: "search_and_retrieve",
intents: ["search", "find"],
defaultAgent: "conductor",
estimatedDuration: 2000,
},
{
id: "verification",
intents: ["verify", "check"],
defaultAgent: "review",
estimatedDuration: 3000,
},
{
id: "deployment",
intents: ["deploy", "release"],
defaultAgent: "deploy",
estimatedDuration: 10000,
},
];
/**
*
*
* @param state - θ
* @param analysis -
* @returns
*/
export async function decide(
state: ThetaCycleState,
analysis?: AnalysisResult,
): Promise<{ state: ThetaCycleState; result: DecisionResult }> {
const { runId } = state;
// フェーズ開始イベント
emitPhaseEvent(runId, ThetaEventType.PHASE_START, {
phase: ThetaPhase.DECIDE,
});
try {
// 分析結果の取得
const analysisResult = analysis ?? (state.context.get("analyze.result") as AnalysisResult);
if (!analysisResult) {
throw new Error("Analysis result not found");
}
// 処理方針の決定
const strategy = selectStrategy(analysisResult.intent);
// エージェントの選択
const agent = selectAgent(analysisResult.intent);
// パラメータの構築
const params = buildParams(analysisResult, strategy);
// 推定実行時間の設定
const strategyDef = AVAILABLE_STRATEGIES.find((s) => s.id === strategy);
const estimatedDuration = strategyDef?.estimatedDuration;
const result: DecisionResult = {
strategy,
agent,
params,
estimatedDuration,
};
// 決定イベント記録
const decisionEvent: ThetaEvent = {
runId,
phase: ThetaPhase.DECIDE,
timestamp: Date.now(),
type: ThetaEventType.DECISION,
data: {
result,
},
};
state.events.push(decisionEvent);
state.currentPhase = ThetaPhase.DECIDE;
state.context.set("decide.result", result);
// Agentイベントを発行
emitAgentEvent({
runId,
stream: "tool",
data: {
type: "decide",
strategy,
agent,
params,
},
});
// フェーズ完了イベント
emitPhaseEvent(runId, ThetaEventType.PHASE_COMPLETE, {
phase: ThetaPhase.DECIDE,
strategy,
agent,
});
return { state, result };
} catch (error) {
// エラーイベント
emitPhaseEvent(runId, ThetaEventType.PHASE_ERROR, {
phase: ThetaPhase.DECIDE,
error: error instanceof Error ? error.message : String(error),
});
throw error;
}
}
/**
*
*/
function selectStrategy(intent: string): string {
const strategy = AVAILABLE_STRATEGIES.find((s) => s.intents.includes(intent));
return strategy?.id ?? "default";
}
/**
*
*/
function selectAgent(intent: string): string | undefined {
const agent = AVAILABLE_AGENTS.find((a) => a.intents.includes(intent) || a.intents.includes("*"));
return agent?.id;
}
/**
*
*/
function buildParams(analysis: AnalysisResult, strategy: string): Record<string, unknown> {
return {
intent: analysis.intent,
entities: analysis.entities,
strategy,
confidence: analysis.confidence,
timestamp: Date.now(),
};
}
/**
*
*
* @param state - θ
* @returns
*/
export function getDecisionResult(state: ThetaCycleState): DecisionResult | undefined {
return state.context.get("decide.result") as DecisionResult | undefined;
}
/**
*
*/
export function getAvailableAgents(): AgentDefinition[] {
return [...AVAILABLE_AGENTS];
}
/**
*
*/
export function getAvailableStrategies(): StrategyDefinition[] {
return [...AVAILABLE_STRATEGIES];
}
/**
*
*/
function emitPhaseEvent(runId: string, type: ThetaEventType, data: Record<string, unknown>): void {
emitAgentEvent({
runId,
stream: "tool",
data: {
type: "theta_event",
thetaEventType: type,
...data,
},
});
}

253
src/theta/execute.ts Normal file
View File

@ -0,0 +1,253 @@
/**
* θ EXECUTE: 実行()
*
*
*
*/
import { emitAgentEvent } from "../infra/agent-events.js";
import {
type DecisionResult,
ThetaCycleState,
ThetaEvent,
ThetaEventType,
ThetaPhase,
} from "./types.js";
import type { ExecuteOptions, ExecutionResult } from "./types.js";
// 型のエクスポート
export type { ExecuteOptions, ExecutionResult };
/**
*
*/
const DEFAULT_OPTIONS: ExecuteOptions = {
timeout: 30000, // 30秒
retries: 3,
};
/**
*
*
* @param state - θ
* @param decision -
* @param executor -
* @param options -
* @returns
*/
export async function execute<T = unknown>(
state: ThetaCycleState,
decision: DecisionResult,
executor: (params: Record<string, unknown>) => Promise<T>,
options?: Partial<ExecuteOptions>,
): Promise<{ state: ThetaCycleState; result: ExecutionResult }> {
const { runId } = state;
const opts = { ...DEFAULT_OPTIONS, ...options };
// フェーズ開始イベント
emitPhaseEvent(runId, ThetaEventType.PHASE_START, {
phase: ThetaPhase.EXECUTE,
strategy: decision.strategy,
agent: decision.agent,
});
const startTime = Date.now();
try {
// リトライ付き実行
const data = await executeWithRetry(
executor,
decision.params,
opts.timeout,
opts.retries,
opts.onProgress,
);
const duration = Date.now() - startTime;
const result: ExecutionResult = {
success: true,
data,
duration,
};
// 実行イベント記録
const executionEvent: ThetaEvent = {
runId,
phase: ThetaPhase.EXECUTE,
timestamp: Date.now(),
type: ThetaEventType.EXECUTION,
data: {
result,
},
};
state.events.push(executionEvent);
state.currentPhase = ThetaPhase.EXECUTE;
state.context.set("execute.result", result);
// Agentイベントを発行
emitAgentEvent({
runId,
stream: "tool",
data: {
type: "execute",
success: true,
duration,
},
});
// フェーズ完了イベント
emitPhaseEvent(runId, ThetaEventType.PHASE_COMPLETE, {
phase: ThetaPhase.EXECUTE,
duration,
});
return { state, result };
} catch (error) {
const duration = Date.now() - startTime;
const execError = error instanceof Error ? error : new Error(String(error));
const result: ExecutionResult = {
success: false,
error: execError,
duration,
};
// 実行エラーイベント記録
const executionEvent: ThetaEvent = {
runId,
phase: ThetaPhase.EXECUTE,
timestamp: Date.now(),
type: ThetaEventType.EXECUTION,
data: {
result,
},
};
state.events.push(executionEvent);
state.context.set("execute.result", result);
// エラーイベント
emitPhaseEvent(runId, ThetaEventType.PHASE_ERROR, {
phase: ThetaPhase.EXECUTE,
error: execError.message,
duration,
});
return { state, result };
}
}
/**
*
*/
async function executeWithRetry<T>(
executor: (params: Record<string, unknown>) => Promise<T>,
params: Record<string, unknown>,
timeout: number,
retries: number,
onProgress?: (progress: number) => void,
): Promise<T> {
let lastError: Error | null = null;
for (let attempt = 0; attempt <= retries; attempt++) {
try {
// 進度通知
onProgress?.(attempt / (retries + 1));
// タイムアウト付き実行
const result = await withTimeout(executor(params), timeout);
return result;
} catch (error) {
lastError = error instanceof Error ? error : new Error(String(error));
// 最後の試行で失敗した場合はエラーを投げる
if (attempt >= retries) {
throw new Error(`Execution failed after ${retries + 1} attempts: ${lastError.message}`);
}
// 指数バックオフで待機
const delay = Math.min(1000 * 2 ** attempt, 10000);
await sleep(delay);
}
}
throw lastError ?? new Error("Execution failed");
}
/**
*
*/
function withTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T> {
return Promise.race([
promise,
new Promise<T>((_, reject) =>
setTimeout(() => reject(new Error(`Timeout after ${timeoutMs}ms`)), timeoutMs),
),
]);
}
/**
*
*/
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
*
*
* @param state - θ
* @returns
*/
export function getExecutionResult(state: ThetaCycleState): ExecutionResult | undefined {
return state.context.get("execute.result") as ExecutionResult | undefined;
}
/**
*
*/
function emitPhaseEvent(runId: string, type: ThetaEventType, data: Record<string, unknown>): void {
emitAgentEvent({
runId,
stream: "tool",
data: {
type: "theta_event",
thetaEventType: type,
...data,
},
});
}
/**
*
*
* @param state - θ
* @param decision -
* @param executor -
* @param options -
* @returns ID使
*/
export function executeBackground<T = unknown>(
state: ThetaCycleState,
decision: DecisionResult,
executor: (params: Record<string, unknown>) => Promise<T>,
options?: Partial<ExecuteOptions>,
): string {
const executionId = `bg_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
// 非同期実行(エラーは無視)
execute(state, decision, executor, options).catch(() => {
// バックグラウンド実行のエラーはログのみ記録
emitAgentEvent({
runId: state.runId,
stream: "error",
data: {
type: "background_execution_error",
executionId,
},
});
});
return executionId;
}

279
src/theta/improve.ts Normal file
View File

@ -0,0 +1,279 @@
/**
* θ IMPROVE: ログ照合
*
*
*
*/
import { emitAgentEvent } from "../infra/agent-events.js";
import { ThetaCycleState, ThetaEvent, ThetaEventType, ThetaPhase } from "./types.js";
import type { AnalysisResult, ImprovementSuggestion, VerificationResult } from "./types.js";
// 型のエクスポート
export type { ImprovementSuggestion };
/**
*
*/
interface ImprovementPattern {
/** パターンID */
id: string;
/** パターンマッチ条件 */
match: (context: ThetaCycleState) => boolean;
/** 改善提案生成関数 */
suggest: (context: ThetaCycleState) => ImprovementSuggestion;
}
/** デフォルトの改善パターン一覧 */
const DEFAULT_IMPROVEMENT_PATTERNS: ImprovementPattern[] = [
{
id: "failed_execution",
match: (ctx) => {
const result = ctx.context.get("execute.result") as { success?: boolean } | undefined;
return result?.success === false;
},
suggest: () => ({
suggestion:
"Execution failed. Review error logs and consider retry with different parameters.",
target: "execution",
priority: "high",
}),
},
{
id: "low_quality_score",
match: (ctx) => {
const result = ctx.context.get("verify.result") as VerificationResult | undefined;
return result?.qualityScore !== undefined && result.qualityScore < 0.6;
},
suggest: (ctx) => {
const result = ctx.context.get("verify.result") as VerificationResult | undefined;
return {
suggestion: `Quality score below threshold (${result?.qualityScore?.toFixed(2)}). Review failed checks: ${result?.failures?.join(", ")}`,
target: "quality",
priority: "medium",
};
},
},
{
id: "slow_execution",
match: (ctx) => {
const result = ctx.context.get("execute.result") as { duration?: number } | undefined;
return result?.duration !== undefined && result.duration > 10000; // 10秒超過
},
suggest: (ctx) => {
const result = ctx.context.get("execute.result") as { duration?: number } | undefined;
return {
suggestion: `Execution took ${result?.duration}ms. Consider optimization or caching.`,
target: "performance",
priority: "low",
metadata: { duration: result?.duration },
};
},
},
{
id: "unknown_intent",
match: (ctx) => {
const result = ctx.context.get("analyze.result") as AnalysisResult | undefined;
return result?.intent === "unknown";
},
suggest: () => ({
suggestion:
"Intent was not recognized. Consider expanding intent patterns or adding training data.",
target: "analysis",
priority: "medium",
}),
},
{
id: "low_confidence",
match: (ctx) => {
const result = ctx.context.get("analyze.result") as AnalysisResult | undefined;
return result?.confidence !== undefined && result.confidence < 0.5;
},
suggest: (ctx) => {
const result = ctx.context.get("analyze.result") as AnalysisResult | undefined;
return {
suggestion: `Analysis confidence low (${result?.confidence?.toFixed(2)}). Additional context may improve accuracy.`,
target: "analysis",
priority: "low",
metadata: { confidence: result?.confidence },
};
},
},
{
id: "successful_execution",
match: (ctx) => {
const execResult = ctx.context.get("execute.result") as { success?: boolean } | undefined;
const verifyResult = ctx.context.get("verify.result") as VerificationResult | undefined;
return execResult?.success === true && verifyResult?.passed === true;
},
suggest: () => ({
suggestion:
"Execution completed successfully. Consider documenting this pattern for future reference.",
target: "documentation",
priority: "low",
}),
},
];
/**
*
*
* @param state - θ
* @param customPatterns -
* @returns
*/
export async function improve(
state: ThetaCycleState,
customPatterns?: ImprovementPattern[],
): Promise<{ state: ThetaCycleState; suggestions: ImprovementSuggestion[] }> {
const { runId } = state;
// フェーズ開始イベント
emitPhaseEvent(runId, ThetaEventType.PHASE_START, {
phase: ThetaPhase.IMPROVE,
});
try {
// 改善パターンの評価
const patterns = customPatterns ?? DEFAULT_IMPROVEMENT_PATTERNS;
const suggestions: ImprovementSuggestion[] = [];
for (const pattern of patterns) {
if (pattern.match(state)) {
suggestions.push(pattern.suggest(state));
}
}
// 改善イベント記録
const improvementEvent: ThetaEvent = {
runId,
phase: ThetaPhase.IMPROVE,
timestamp: Date.now(),
type: ThetaEventType.IMPROVEMENT,
data: {
suggestions,
count: suggestions.length,
},
};
state.events.push(improvementEvent);
state.currentPhase = ThetaPhase.IMPROVE;
state.context.set("improve.suggestions", suggestions);
// Agentイベントを発行
emitAgentEvent({
runId,
stream: "tool",
data: {
type: "improve",
suggestions,
count: suggestions.length,
},
});
// フェーズ完了イベント
emitPhaseEvent(runId, ThetaEventType.PHASE_COMPLETE, {
phase: ThetaPhase.IMPROVE,
suggestionCount: suggestions.length,
});
return { state, suggestions };
} catch (error) {
// エラーイベント
emitPhaseEvent(runId, ThetaEventType.PHASE_ERROR, {
phase: ThetaPhase.IMPROVE,
error: error instanceof Error ? error.message : String(error),
});
throw error;
}
}
/**
*
*
* @param state - θ
* @returns
*/
export function getImprovementSuggestions(state: ThetaCycleState): ImprovementSuggestion[] {
return (state.context.get("improve.suggestions") as ImprovementSuggestion[]) ?? [];
}
/**
*
*
* @param patterns -
* @param newPattern -
* @returns
*/
export function addImprovementPattern(
patterns: ImprovementPattern[],
newPattern: ImprovementPattern,
): ImprovementPattern[] {
return [...patterns, newPattern];
}
/**
*
*
* @param id - ID
* @param match -
* @param suggest -
* @returns
*/
export function createImprovementPattern(
id: string,
match: (context: ThetaCycleState) => boolean,
suggest: (context: ThetaCycleState) => ImprovementSuggestion,
): ImprovementPattern {
return { id, match, suggest };
}
/**
*
*
* @param state - θ
* @returns
*/
export function generateCycleSummary(state: ThetaCycleState): {
runId: string;
duration: number;
phases: ThetaPhase[];
eventCount: number;
success: boolean;
suggestions: ImprovementSuggestion[];
} {
const startTime = state.startTime;
const endTime = Date.now();
const duration = endTime - startTime;
const phases = state.events.map((e) => e.phase).filter((p, i, arr) => arr.indexOf(p) === i); // ユニークなフェーズのみ
const executionResult = state.context.get("execute.result") as { success?: boolean } | undefined;
const success = executionResult?.success ?? false;
const suggestions = getImprovementSuggestions(state);
return {
runId: state.runId,
duration,
phases,
eventCount: state.events.length,
success,
suggestions,
};
}
/**
*
*/
function emitPhaseEvent(runId: string, type: ThetaEventType, data: Record<string, unknown>): void {
emitAgentEvent({
runId,
stream: "tool",
data: {
type: "theta_event",
thetaEventType: type,
...data,
},
});
}

261
src/theta/index.ts Normal file
View File

@ -0,0 +1,261 @@
/**
* θ (Theta Cycle) -
*
* Agent(Intent, World) = lim_{n} (θ θ θ θ θ θ)
*
* θ
*/
// 型定義のエクスポート
export type {
// 共通型
ThetaCycleState,
ThetaCycleOptions,
ThetaEvent,
ThetaEventType,
// 各フェーズ関連
ObserveContext,
AnalysisResult,
DecisionResult,
ExecuteOptions,
ExecutionResult,
VerificationResult,
ImprovementSuggestion,
} from "./types.js";
export { ThetaPhase } from "./types.js";
// θ₁ OBSERVE
export { observe, handleReaction, getObservations } from "./observe.js";
// θ₂ ANALYZE
export { analyze, getAnalysisResult } from "./analyze.js";
// θ₃ DECIDE
export { decide, getDecisionResult, getAvailableAgents, getAvailableStrategies } from "./decide.js";
// θ₄ EXECUTE
export { execute, executeBackground, getExecutionResult } from "./execute.js";
// θ₅ VERIFY
export { verify, getVerificationResult, addQualityCheck, createQualityCheck } from "./verify.js";
// θ₆ IMPROVE
export {
improve,
getImprovementSuggestions,
addImprovementPattern,
createImprovementPattern,
generateCycleSummary,
} from "./improve.js";
// 完全なサイクル実行
import { observe, handleReaction, type ObserveContext } from "./observe.js";
import { analyze, type AnalysisResult } from "./analyze.js";
import { decide, type DecisionResult } from "./decide.js";
import { execute, type ExecuteOptions, type ExecutionResult } from "./execute.js";
import { verify, type VerificationResult } from "./verify.js";
import { improve, generateCycleSummary, type ImprovementSuggestion } from "./improve.js";
import type { ThetaCycleOptions, ThetaCycleState } from "./types.js";
import { ThetaPhase } from "./types.js";
/**
* θ
*/
export function createThetaCycleState(runId: string, options?: ThetaCycleOptions): ThetaCycleState {
return {
runId,
startTime: Date.now(),
currentPhase: null,
events: [],
context: new Map(),
};
}
/**
* θ
*
* @param input -
* @param executor -
* @param options -
* @returns
*/
export async function runThetaCycle<T = unknown>(
input: unknown,
executor: (params: Record<string, unknown>) => Promise<T>,
options?: ThetaCycleOptions & Partial<ExecuteOptions>,
): Promise<{
state: ThetaCycleState;
analysis: AnalysisResult;
decision: DecisionResult;
execution: ExecutionResult;
verification: VerificationResult;
suggestions: ImprovementSuggestion[];
}> {
const runId = `theta_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
const state = createThetaCycleState(runId, options);
// オプションのマージ
const timeout = options?.defaultTimeout ?? 30000;
const retries = options?.defaultRetries ?? 3;
// θ₁ OBSERVE
const observeState = await observe(state, { input });
// θ₂ ANALYZE
const analyzeResult = await analyze(observeState);
const analyzeState = analyzeResult.state;
// θ₃ DECIDE
const decideResult = await decide(analyzeState);
const decideState = decideResult.state;
// θ₄ EXECUTE
const executeResult = await execute<T>(decideState, decideResult.result, executor, {
timeout,
retries,
});
const executeState = executeResult.state;
// θ₅ VERIFY
const verifyResult = await verify(executeState);
const verifyState = verifyResult.state;
// θ₆ IMPROVE
const improveResult = await improve(verifyState);
const improveState = improveResult.state;
// サマリー生成
const summary = generateCycleSummary(improveState);
// オプションのコールバック
if (options?.onEvent) {
for (const event of improveState.events) {
options.onEvent(event);
}
}
return {
state: improveState,
analysis: analyzeResult.result,
decision: decideResult.result,
execution: executeResult.result,
verification: verifyResult.result,
suggestions: improveResult.suggestions,
};
}
/**
* θ
*
*
* @param input -
* @param executor -
* @param onPhase -
* @param options -
* @returns
*/
export async function runThetaCycleStream<T = unknown>(
input: unknown,
executor: (params: Record<string, unknown>) => Promise<T>,
onPhase: (phase: ThetaPhase, data: unknown) => void,
options?: ThetaCycleOptions & Partial<ExecuteOptions>,
): Promise<{
state: ThetaCycleState;
analysis: AnalysisResult;
decision: DecisionResult;
execution: ExecutionResult;
verification: VerificationResult;
suggestions: ImprovementSuggestion[];
}> {
const runId = `theta_stream_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
const state = createThetaCycleState(runId, options);
const timeout = options?.defaultTimeout ?? 30000;
const retries = options?.defaultRetries ?? 3;
// θ₁ OBSERVE
let currentState = await observe(state, { input });
onPhase(ThetaPhase.OBSERVE, currentState.events);
// θ₂ ANALYZE
const analyzeResult = await analyze(currentState);
currentState = analyzeResult.state;
onPhase(ThetaPhase.ANALYZE, analyzeResult.result);
// θ₃ DECIDE
const decideResult = await decide(currentState);
currentState = decideResult.state;
onPhase(ThetaPhase.DECIDE, decideResult.result);
// θ₄ EXECUTE
const executeResult = await execute<T>(currentState, decideResult.result, executor, {
timeout,
retries,
});
currentState = executeResult.state;
onPhase(ThetaPhase.EXECUTE, executeResult.result);
// θ₅ VERIFY
const verifyResult = await verify(currentState);
currentState = verifyResult.state;
onPhase(ThetaPhase.VERIFY, verifyResult.result);
// θ₆ IMPROVE
const improveResult = await improve(currentState);
currentState = improveResult.state;
onPhase(ThetaPhase.IMPROVE, improveResult.suggestions);
return {
state: currentState,
analysis: analyzeResult.result,
decision: decideResult.result,
execution: executeResult.result,
verification: verifyResult.result,
suggestions: improveResult.suggestions,
};
}
/**
* θ/
*
* @param state -
* @returns
*/
export function createCheckpoint(state: ThetaCycleState): {
runId: string;
startTime: number;
currentPhase: ThetaPhase | null;
context: Record<string, unknown>;
eventCount: number;
} {
return {
runId: state.runId,
startTime: state.startTime,
currentPhase: state.currentPhase,
context: Object.fromEntries(state.context.entries()),
eventCount: state.events.length,
};
}
/**
*
*
* @param checkpoint -
* @returns
*/
export function restoreFromCheckpoint(checkpoint: {
runId: string;
startTime: number;
currentPhase: ThetaPhase | null;
context: Record<string, unknown>;
}): ThetaCycleState {
return {
runId: checkpoint.runId,
startTime: checkpoint.startTime,
currentPhase: checkpoint.currentPhase,
events: [],
context: new Map(Object.entries(checkpoint.context)),
};
}

152
src/theta/observe.ts Normal file
View File

@ -0,0 +1,152 @@
/**
* θ OBSERVE: イベントログ記録
*
*
*
*/
import { emitAgentEvent } from "../infra/agent-events.js";
import {
type ObserveContext,
ThetaCycleState,
ThetaEvent,
ThetaEventType,
ThetaPhase,
} from "./types.js";
/**
*
*
* @param state - θ
* @param context -
* @returns
*/
export async function observe(
state: ThetaCycleState,
context: ObserveContext,
): Promise<ThetaCycleState> {
const { runId } = state;
// フェーズ開始イベント
emitPhaseEvent(runId, ThetaEventType.PHASE_START, {
phase: ThetaPhase.OBSERVE,
input: context.input,
});
try {
// 入力データの観測
const observation: ThetaEvent = {
runId,
phase: ThetaPhase.OBSERVE,
timestamp: Date.now(),
type: ThetaEventType.OBSERVATION,
data: {
input: context.input,
metadata: context.metadata,
sessionKey: context.sessionKey,
},
};
// 状態を更新
state.events.push(observation);
state.currentPhase = ThetaPhase.OBSERVE;
state.context.set("observe.input", context.input);
state.context.set("observe.metadata", context.metadata);
// Agentイベントを発行
emitAgentEvent({
runId,
stream: "tool",
data: {
type: "observe",
input: context.input,
},
});
// フェーズ完了イベント
emitPhaseEvent(runId, ThetaEventType.PHASE_COMPLETE, {
phase: ThetaPhase.OBSERVE,
observationCount: 1,
});
return state;
} catch (error) {
// エラーイベント
emitPhaseEvent(runId, ThetaEventType.PHASE_ERROR, {
phase: ThetaPhase.OBSERVE,
error: error instanceof Error ? error.message : String(error),
});
throw error;
}
}
/**
*
*
* @param state - θ
* @param reaction -
* @returns
*/
export async function handleReaction(
state: ThetaCycleState,
reaction: Record<string, unknown>,
): Promise<ThetaCycleState> {
const { runId } = state;
// リアクション記録
const reactionEvent: ThetaEvent = {
runId,
phase: ThetaPhase.OBSERVE,
timestamp: Date.now(),
type: ThetaEventType.OBSERVATION,
data: {
type: "reaction",
reaction,
},
};
state.events.push(reactionEvent);
state.context.set("observe.reaction", reaction);
// Agentイベントを発行
emitAgentEvent({
runId,
stream: "tool",
data: {
type: "reaction",
reaction,
},
});
return state;
}
/**
*
*/
function emitPhaseEvent(runId: string, type: ThetaEventType, data: Record<string, unknown>): void {
emitAgentEvent({
runId,
stream: "tool",
data: {
type: "theta_event",
thetaEventType: type,
...data,
},
});
}
/**
*
*
* @param state - θ
* @returns
*/
export function getObservations(state: ThetaCycleState): ThetaEvent[] {
return state.events.filter(
(e) => e.phase === ThetaPhase.OBSERVE && e.type === ThetaEventType.OBSERVATION,
);
}
// 型のエクスポート
export type { ObserveContext };

181
src/theta/types.ts Normal file
View File

@ -0,0 +1,181 @@
/**
* θ (Theta Cycle)
*
* Agent(Intent, World) = lim_{n} (θ θ θ θ θ θ)
*/
/**
* θ
*/
export enum ThetaPhase {
OBSERVE = "θ₁ OBSERVE",
ANALYZE = "θ₂ ANALYZE",
DECIDE = "θ₃ DECIDE",
EXECUTE = "θ₄ EXECUTE",
VERIFY = "θ₅ VERIFY",
IMPROVE = "θ₆ IMPROVE",
}
/**
*
*/
export interface ThetaEvent {
/** 実行ID */
runId: string;
/** フェーズ */
phase: ThetaPhase;
/** タイムスタンプ */
timestamp: number;
/** イベント種別 */
type: ThetaEventType;
/** データ */
data: Record<string, unknown>;
}
/**
*
*/
export enum ThetaEventType {
/** フェーズ開始 */
PHASE_START = "phase_start",
/** フェーズ完了 */
PHASE_COMPLETE = "phase_complete",
/** フェーズエラー */
PHASE_ERROR = "phase_error",
/** 観測データ記録 */
OBSERVATION = "observation",
/** 分析結果 */
ANALYSIS = "analysis",
/** 決定 */
DECISION = "decision",
/** 実行結果 */
EXECUTION = "execution",
/** 検証結果 */
VERIFICATION = "verification",
/** 改善提案 */
IMPROVEMENT = "improvement",
}
/**
* (OBSERVE用)
*/
export interface ObserveContext {
/** セッションキー */
sessionKey?: string;
/** 入力データ */
input: unknown;
/** メタデータ */
metadata?: Record<string, unknown>;
}
/**
* (ANALYZE用)
*/
export interface AnalysisResult {
/** 意図解析結果 */
intent: string;
/** 抽出されたエンティティ */
entities: Record<string, unknown>;
/** コンテキスト情報 */
context: Record<string, unknown>;
/** 信頼度 */
confidence: number;
}
/**
* (DECIDE用)
*/
export interface DecisionResult {
/** 選択された処理方針 */
strategy: string;
/** 選択されたエージェント */
agent?: string;
/** パラメータ */
params: Record<string, unknown>;
/** 推定実行時間(ms) */
estimatedDuration?: number;
}
/**
* (EXECUTE用)
*/
export interface ExecuteOptions {
/** タイムアウト(ms) */
timeout: number;
/** リトライ回数 */
retries: number;
/** 进度回调 */
onProgress?: (progress: number) => void;
}
/**
* (EXECUTE用)
*/
export interface ExecutionResult {
/** 成功判定 */
success: boolean;
/** 結果データ */
data?: unknown;
/** エラー情報 */
error?: Error;
/** 実行時間(ms) */
duration: number;
}
/**
* (VERIFY用)
*/
export interface VerificationResult {
/** 検証パス */
passed: boolean;
/** 品質スコア (0-1) */
qualityScore: number;
/** 検証項目ごとの結果 */
checks: Record<string, boolean>;
/** 失敗理由 */
failures?: string[];
}
/**
* (IMPROVE用)
*/
export interface ImprovementSuggestion {
/** 改善内容 */
suggestion: string;
/** 適用対象 */
target: string;
/** 優先度 */
priority: "low" | "medium" | "high";
/** メタデータ */
metadata?: Record<string, unknown>;
}
/**
* θ
*/
export interface ThetaCycleState {
/** 実行ID */
runId: string;
/** 開始時刻 */
startTime: number;
/** 現在のフェーズ */
currentPhase: ThetaPhase | null;
/** イベントログ */
events: ThetaEvent[];
/** コンテキスト */
context: Map<string, unknown>;
}
/**
* θ
*/
export interface ThetaCycleOptions {
/** デフォルトタイムアウト(ms) */
defaultTimeout?: number;
/** デフォルトリトライ回数 */
defaultRetries?: number;
/** 詳細ログレベル */
verbose?: boolean;
/** カスタムイベントハンドラ */
onEvent?: (event: ThetaEvent) => void;
}

213
src/theta/verify.ts Normal file
View File

@ -0,0 +1,213 @@
/**
* θ VERIFY: 結果検証
*
*
*/
import { emitAgentEvent } from "../infra/agent-events.js";
import {
type ExecutionResult,
ThetaCycleState,
ThetaEvent,
ThetaEventType,
ThetaPhase,
} from "./types.js";
import type { VerificationResult } from "./types.js";
// 型のエクスポート
export type { VerificationResult };
/**
*
*/
interface QualityCheck {
/** チェック名 */
name: string;
/** チェック関数 */
check: (result: ExecutionResult) => boolean | Promise<boolean>;
/** 重大度 */
severity: "critical" | "major" | "minor";
}
/** デフォルトの品質チェック一覧 */
const DEFAULT_QUALITY_CHECKS: QualityCheck[] = [
{
name: "execution_success",
check: (result) => result.success,
severity: "critical",
},
{
name: "has_output",
check: (result) => result.data !== undefined && result.data !== null,
severity: "major",
},
{
name: "reasonable_duration",
check: (result) => result.duration < 60000, // 1分以内
severity: "minor",
},
{
name: "no_critical_errors",
check: (result) => {
if (!result.error) return true;
const errorMsg = result.error.message.toLowerCase();
return !errorMsg.includes("critical") && !errorMsg.includes("fatal");
},
severity: "critical",
},
];
/**
*
*
* @param state - θ
* @param customChecks -
* @returns
*/
export async function verify(
state: ThetaCycleState,
customChecks?: QualityCheck[],
): Promise<{ state: ThetaCycleState; result: VerificationResult }> {
const { runId } = state;
// フェーズ開始イベント
emitPhaseEvent(runId, ThetaEventType.PHASE_START, {
phase: ThetaPhase.VERIFY,
});
try {
// 実行結果の取得
const executionResult = state.context.get("execute.result") as ExecutionResult | undefined;
if (!executionResult) {
throw new Error("Execution result not found");
}
// 品質チェックの実行
const checks = customChecks ?? DEFAULT_QUALITY_CHECKS;
const checkResults: Record<string, boolean> = {};
const failures: string[] = [];
let totalScore = 0;
let totalWeight = 0;
for (const check of checks) {
const passed = await check.check(executionResult);
checkResults[check.name] = passed;
// 重み付けcritical: 5, major: 3, minor: 1
const weight = check.severity === "critical" ? 5 : check.severity === "major" ? 3 : 1;
totalWeight += weight;
if (passed) {
totalScore += weight;
} else {
failures.push(`${check.name} (${check.severity})`);
}
}
// 品質スコアの計算 (0-1)
const qualityScore = totalWeight > 0 ? totalScore / totalWeight : 0;
const result: VerificationResult = {
passed: qualityScore >= 0.6, // 60%以上でパス
qualityScore,
checks: checkResults,
failures: failures.length > 0 ? failures : undefined,
};
// 検証イベント記録
const verificationEvent: ThetaEvent = {
runId,
phase: ThetaPhase.VERIFY,
timestamp: Date.now(),
type: ThetaEventType.VERIFICATION,
data: {
result,
},
};
state.events.push(verificationEvent);
state.currentPhase = ThetaPhase.VERIFY;
state.context.set("verify.result", result);
// Agentイベントを発行
emitAgentEvent({
runId,
stream: "tool",
data: {
type: "verify",
passed: result.passed,
qualityScore: result.qualityScore,
failures: result.failures,
},
});
// フェーズ完了イベント
emitPhaseEvent(runId, ThetaEventType.PHASE_COMPLETE, {
phase: ThetaPhase.VERIFY,
passed: result.passed,
qualityScore: result.qualityScore,
});
return { state, result };
} catch (error) {
// エラーイベント
emitPhaseEvent(runId, ThetaEventType.PHASE_ERROR, {
phase: ThetaPhase.VERIFY,
error: error instanceof Error ? error.message : String(error),
});
throw error;
}
}
/**
*
*
* @param state - θ
* @returns
*/
export function getVerificationResult(state: ThetaCycleState): VerificationResult | undefined {
return state.context.get("verify.result") as VerificationResult | undefined;
}
/**
*
*
* @param checks -
* @param newCheck -
* @returns
*/
export function addQualityCheck(checks: QualityCheck[], newCheck: QualityCheck): QualityCheck[] {
return [...checks, newCheck];
}
/**
*
*
* @param name -
* @param check -
* @param severity -
* @returns
*/
export function createQualityCheck(
name: string,
check: (result: ExecutionResult) => boolean | Promise<boolean>,
severity: "critical" | "major" | "minor" = "major",
): QualityCheck {
return { name, check, severity };
}
/**
*
*/
function emitPhaseEvent(runId: string, type: ThetaEventType, data: Record<string, unknown>): void {
emitAgentEvent({
runId,
stream: "tool",
data: {
type: "theta_event",
thetaEventType: type,
...data,
},
});
}