v2.2.15: Astra Office Refactor & Multi-Service Integration
This commit is contained in:
@@ -108,7 +108,22 @@ export const COMPANY_AGENTS: Record<string, CompanyAgentDef> = {
|
||||
specialty: '일정·마일스톤 관리, 스프린트·간트 차트, 리소스 배분·우선순위 조정, 리스크 추적·완화, 회의 노트·의사결정 로그, 데일리 스탠드업, 다른 에이전트 산출물 요약 보고, 알림·리마인더, 이해관계자 커뮤니케이션',
|
||||
tagline: '일정·리소스·소통을 챙기고 정리합니다',
|
||||
roleCategory: 'support',
|
||||
persona: '친근하고 정중하지만 일정 앞에서는 단호한 톤. 짧고 정리된 문장. 보고할 때는 한눈에 보이게 불릿 + 핵심만 (날짜·담당·상태). 이모지는 😊·📅·✅ 정도.',
|
||||
persona: `친근하고 정중하지만 일정 앞에서는 단호한 톤. 짧고 정리된 문장. 보고할 때는 한눈에 보이게 불릿 + 핵심만 (날짜·담당·상태). 이모지는 😊·📅·✅ 정도.
|
||||
|
||||
**회의록·트랜스크립트·요청 입력 시 자동 분배 패턴 (당신의 핵심 업무):**
|
||||
입력에서 다음 4종을 *각각 따로* 추출하고 *각각의 액션 태그* 로 즉시 emit:
|
||||
|
||||
1. **확정 일정** (시각이 명확한 약속/미팅/마감) → \`<create_calendar_event>\` 로 Google Calendar 등록 + \`<add_task>\` 로 추적기에도 동시 등록.
|
||||
2. **할일** (시각 없거나 모호한 to-do, 책임 명확) → \`<add_task>\` 로 추적기에만 등록. 시각 확정 안 됐으면 due 비움.
|
||||
3. **결정 사항** (방향성·합의) → 별도 액션 없이 답변 본문 "## 결정" 섹션에 한 줄씩 정리 (decisions.md 는 시스템이 자동).
|
||||
4. **시각 모호** ("다음주", "조만간") → 액션 태그 emit 금지. 답변 마지막에 "❓ 확정 필요: …" 로 질문.
|
||||
|
||||
**진척 추적**: 사용자가 "어제 X 끝냈어" / "Y 블락됐어" 같은 보고를 하면 *즉시* \`<update_task>\` 또는 \`<complete_task>\` emit. "잘 챙겨드릴게요" 라고 말만 하지 말고 태그로 실제 갱신.
|
||||
|
||||
**답변 마지막 한 줄 요약** (사용자가 무엇이 등록됐는지 즉시 확인):
|
||||
- 📅 등록: 제목 · 시각
|
||||
- 📋 추가: 제목 · 담당 · 마감
|
||||
- ✅ 완료: 제목`,
|
||||
},
|
||||
writer: {
|
||||
id: 'writer',
|
||||
|
||||
@@ -566,6 +566,21 @@ async function _dispatchOne(
|
||||
}
|
||||
const memory = readAgentMemory(deps.context, agentId);
|
||||
const decisions = readDecisions(deps.context, 2000);
|
||||
// Google Calendar iCal 캐시 (선택 사항). 셋업 안 된 사용자는 빈 문자열 → 무시.
|
||||
// 매 dispatch 마다 디스크 read 1회 발생하지만 캐시는 KB 단위라 비용 무시 가능.
|
||||
let calendarContext = '';
|
||||
try {
|
||||
const { readCalendarCache } = require('../calendar') as typeof import('../calendar');
|
||||
calendarContext = readCalendarCache(deps.context) ?? '';
|
||||
} catch { /* feature 미설치 / 캐시 없음 — silent skip */ }
|
||||
|
||||
// Task tracker — _shared/tasks.md 의 active 항목 요약. 모든 agent 가 진척 상황을
|
||||
// 한 눈에 볼 수 있도록. 비어있으면 빈 문자열 → 프롬프트에서 섹션 자체 생략.
|
||||
let tasksContext = '';
|
||||
try {
|
||||
const { readTaskStore, summarizeActiveTasks } = require('../tasks') as typeof import('../tasks');
|
||||
tasksContext = summarizeActiveTasks(readTaskStore(deps.context));
|
||||
} catch { /* silent */ }
|
||||
const peerOutputs = earlierOutputs
|
||||
.filter((o) => !o.error) // skip failed peers — they'd just confuse the next agent
|
||||
.map((o) => {
|
||||
@@ -624,6 +639,8 @@ async function _dispatchOne(
|
||||
const system = buildSpecialistPrompt({
|
||||
agentId, state,
|
||||
agentMemory: memory, sharedDecisions: decisions,
|
||||
calendarContext,
|
||||
tasksContext,
|
||||
peerOutputs,
|
||||
brainContext, // injected as `[SECOND BRAIN CONTEXT]` block
|
||||
knowledgeMixPolicy: policyBlock, // injected as `[KNOWLEDGE MIX POLICY]` block
|
||||
|
||||
@@ -239,12 +239,40 @@ const PLAN_ONLY: PipelineTemplate = {
|
||||
],
|
||||
};
|
||||
|
||||
/** Read-only registry of templates the UI surfaces. Add more here later. */
|
||||
/**
|
||||
* "개발까지만" — FULL_PRODUCT_DEV 의 1~10 단계 (plan-discuss ~ dev-impl) 만 진행.
|
||||
* QA·배포는 사용자가 코드 받아본 뒤 수동 처리하길 원하는 경우. dev-impl 종료
|
||||
* 직후 CEO 합산 보고로 turn 종료. design-review 의 dev-design loop-back 은 유지.
|
||||
*
|
||||
* stages 는 FULL_PRODUCT_DEV.stages.slice(0, 10) 으로 *참조 공유* — 사용자가
|
||||
* 템플릿 stamp 시 deep-copy 되므로 본 정의 객체는 read-only 안전.
|
||||
*/
|
||||
const DEV_ONLY: PipelineTemplate = {
|
||||
templateId: 'dev-only',
|
||||
name: '개발까지만 (10단계)',
|
||||
description: '풀 워크플로에서 QA·배포 단계를 뺀 버전. 기획 → 개발까지 만들고 검증·배포는 사용자가 직접 챙깁니다.',
|
||||
suggestedPipelineId: 'dev-only',
|
||||
suggestedPipelineName: '기획→개발 파이프라인',
|
||||
stages: FULL_PRODUCT_DEV.stages.slice(0, 10),
|
||||
};
|
||||
|
||||
/** Read-only registry of templates the UI surfaces. */
|
||||
export const PIPELINE_TEMPLATES: PipelineTemplate[] = [
|
||||
FULL_PRODUCT_DEV,
|
||||
PLAN_ONLY,
|
||||
DEV_ONLY,
|
||||
FULL_PRODUCT_DEV,
|
||||
];
|
||||
|
||||
/**
|
||||
* 스코프 단축 표기 — 사용자가 사이드바에서 한 번에 보고 선택할 수 있는 3-way 라벨.
|
||||
* 각 키는 PIPELINE_TEMPLATES 의 templateId 와 1:1. 매핑 변경 시 UI 동기화 필요.
|
||||
*/
|
||||
export const SCOPE_PRESETS = [
|
||||
{ templateId: 'plan-only', shortLabel: '기획만', longLabel: '기획서까지만' },
|
||||
{ templateId: 'dev-only', shortLabel: '개발까지', longLabel: '개발까지만' },
|
||||
{ templateId: 'full-product-dev', shortLabel: '풀', longLabel: '배포까지 풀 파이프라인' },
|
||||
] as const;
|
||||
|
||||
export function getPipelineTemplate(id: string): PipelineTemplate | undefined {
|
||||
return PIPELINE_TEMPLATES.find((t) => t.templateId === id);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,18 @@ export interface SpecialistPromptInputs {
|
||||
agentMemory?: string;
|
||||
/** Tail of `_shared/decisions.md` (may be empty). */
|
||||
sharedDecisions?: string;
|
||||
/**
|
||||
* `_shared/calendar_cache.md` 내용 (Google Calendar iCal 읽기 전용 feature).
|
||||
* 비어있으면 prompt 에 섹션 추가 안 함. 모든 agent 가 동일하게 받음 — 일정·운영을
|
||||
* 다루는 secretary 직군이 가장 활용 가능성 높지만, 기획·개발도 "이번 주 빈 슬롯"
|
||||
* 같은 추론에 쓸 수 있음.
|
||||
*/
|
||||
calendarContext?: string;
|
||||
/**
|
||||
* Task tracker (`_shared/tasks.md`) active 항목 요약. 모든 agent 가 진척 상황 + 막힌
|
||||
* task 를 인지하고 일을 분배·재조정. 비어있으면 섹션 생략.
|
||||
*/
|
||||
tasksContext?: string;
|
||||
/**
|
||||
* Peer outputs from earlier agents in *this* dispatch, in execution order.
|
||||
* Truncated by the dispatcher before passing — this builder doesn't trim
|
||||
@@ -121,6 +133,28 @@ export function buildSpecialistPrompt(inputs: SpecialistPromptInputs): string {
|
||||
parts.push(' • `<delete_file path="..."/>` — 파일·디렉토리 삭제');
|
||||
parts.push(' • `<list_files path="..."/>` — 디렉토리 목록 보기');
|
||||
parts.push(' • `<run_command>명령</run_command>` — 셸 실행 (디렉토리 생성 등)');
|
||||
parts.push(' • `<create_calendar_event title="..." start="2026-05-21T14:00" duration="60" location="...">설명</create_calendar_event>` — Google Calendar 일정 자동 생성 (OAuth 연결 필요)');
|
||||
parts.push(' • `<read_sheet spreadsheet_id="..." range="Sheet1!A1:D20"/>` — Google Sheets 셀 범위 읽기');
|
||||
parts.push(' • `<write_sheet spreadsheet_id="..." range="Sheet1!A1">TSV 본문</write_sheet>` — 셀 덮어쓰기 (탭 구분, 줄바꿈 = 행)');
|
||||
parts.push(' • `<append_sheet spreadsheet_id="..." range="Sheet1!A:C">TSV 본문</append_sheet>` — 마지막 데이터 행 아래에 append');
|
||||
parts.push(' • `<add_task title="..." owner="@me" due="2026-05-24T18:00" notes="..."/>` — 작업 추적기에 task 추가');
|
||||
parts.push(' • `<update_task id="t_001" status="in_progress|blocked|done" notes="..."/>` — 진척·blocker 갱신');
|
||||
parts.push(' • `<complete_task id="t_001"/>` — task 완료 처리 (done 섹션으로 이동)');
|
||||
parts.push('');
|
||||
parts.push('📋 **Task 사용 시점**:');
|
||||
parts.push('- 회의록·요청 처리 중 *명확한 할일* 마다 add_task 1개씩 emit. 추측·확장 금지.');
|
||||
parts.push('- 사용자가 진척 보고하면 즉시 update_task / complete_task. "추적해뒀어요" 라고 말만 하지 말 것.');
|
||||
parts.push('- due 가 분 단위로 명확하면 add_task + create_calendar_event 함께 emit — 추적기에도, 캘린더에도.');
|
||||
parts.push('');
|
||||
parts.push('📅 **Calendar 사용 시점**:');
|
||||
parts.push('- 사용자가 회의록 / 안건 / "X 일까지 끝내야 해" 같이 *명확한 시각이 있는* 약속·작업을 공유했을 때.');
|
||||
parts.push('- 시간이 모호하면 ("다음주에", "조만간") 태그 emit 하지 말고 *물어봐서 확정* 한 뒤 emit.');
|
||||
parts.push('- 회의록에 여러 일정/할일이 섞여 있으면 *각각 1개 태그씩* emit. 한 태그에 여러 일정 욱여넣지 말 것.');
|
||||
parts.push('');
|
||||
parts.push('📊 **Sheets 사용 시점**:');
|
||||
parts.push('- spreadsheet_id 는 사용자가 *직접 알려준 것만* 사용. 추측 / 생성 금지.');
|
||||
parts.push('- 쓰기 전엔 한 줄로 "어디에 무엇을 쓰겠다" 미리 보고. 사용자가 stop 안 걸면 즉시 태그 emit.');
|
||||
parts.push('- 본문은 TSV (탭 구분, 줄바꿈 = 행). 한 줄에 칼럼이 여러개면 탭으로 구분.');
|
||||
parts.push('');
|
||||
parts.push('🛑 **경로 규칙 (위반 시 권한 거부됨)**:');
|
||||
parts.push('- 경로는 **워크스페이스 루트 상대 경로**로 쓰세요. 예: `timertest/timer.py`, `src/utils.py`');
|
||||
@@ -188,6 +222,26 @@ export function buildSpecialistPrompt(inputs: SpecialistPromptInputs): string {
|
||||
parts.push(decisions);
|
||||
}
|
||||
|
||||
// ── Google Calendar (iCal 읽기 전용) ──
|
||||
// 모든 agent 가 받는 외부 컨텍스트 — "이번 주 화/목 14:00-16:00 비어있다",
|
||||
// "내일 13:00 미팅" 같은 정보. 캐시 파일은 g1nation.calendar.refresh 명령 또는
|
||||
// 셋업 시점에 갱신됨 — turn 마다 fetch 하면 외부 의존성 + 지연 발생하므로 보수적.
|
||||
const calendarCtx = (inputs.calendarContext ?? '').trim();
|
||||
if (calendarCtx) {
|
||||
parts.push('');
|
||||
parts.push('## 사용자 일정 컨텍스트 (Google Calendar)');
|
||||
parts.push(calendarCtx);
|
||||
}
|
||||
|
||||
// ── Task tracker — active 작업 한 눈에 ──
|
||||
const tasksCtx = (inputs.tasksContext ?? '').trim();
|
||||
if (tasksCtx) {
|
||||
parts.push('');
|
||||
parts.push('## 진행 중인 작업 (tasks.md · active)');
|
||||
parts.push('아래는 회사 작업 추적기에 active 로 들어있는 task 들입니다. 진척 / 막힌 항목 / 다가오는 마감을 인지하고 답변에 반영하세요. 사용자가 진척을 알려주면 `<update_task>` 또는 `<complete_task>` 로 즉시 갱신.');
|
||||
parts.push(tasksCtx);
|
||||
}
|
||||
|
||||
// ── Self-Reflector Phase A 룰 (가장 마지막에 prepend) ──
|
||||
// 답변 끝에 [Self-Reflector Check] 블록을 자동으로 붙이게 만든다. developer
|
||||
// 직군이면 코드 가드 블록도 함께 — undefined variable / 잘못된 경로 같은
|
||||
|
||||
Reference in New Issue
Block a user