콘텐츠로 이동

v0.2.0

릴리스이전 버전
영역변경분류
A2A 에러 처리llamon_agent.core.errors 모듈 신설 — ErrorCode enum + Pydantic 스키마 + raise_application_error() helper + Python 예외 자동 매핑. 플로우 중간 노드 실패 시 artifacts 자동 보존, SSE 중간 실패 자동 failed 마감신규 API (권장) · BREAKING (응답 형태 전환)
A2A DataPart 보존LangGraphAgent 경로 (create_server(agent=None) 또는 flow)에서 상위 에이전트의 DataPart/FilePart 가 최종 응답에 유실되던 버그 수정. executor에 isinstance-gated passthrough helper 추가로 해결. RuntimeAdapter 경로는 바이트 단위로 동일. 스트리밍도 토큰 실시간성 유지하며 최종 청크에 DataPart append. 에이전트 프로젝트 수정 불필요버그 수정
ExtensionConfig.artifact_name / artifact_descriptionconfig.py 한 곳에서 선언적으로 A2A artifact 메타 지정. Registry/Flow/Adapter 3경로 모두 지원. Priority chain: result-level > Adapter ClassVar > ExtensionConfig > fallback heuristic. artifact_name 단독 목적으로 runtime_adapter.py 파일 작성 불필요. 미설정 시 기존 동작과 바이트 단위로 동일. agent-composition 가이드 참조신규 API (DX 개선)
Flow 노드 DXcall_llm(agent, prompt, *, state) / call_agent_auto(url, query, *, state)state.metadata.is_stream_request 자동 감지로 stream/invoke 분기. 기존 10줄 분기 → 1줄DX 개선
Scaffoldnodes.py 상단에 Input Contracts 가이드 주석 자동 삽입 (graph 템플릿 4종)UX
MemoryPostgreSQL 의존성 core 승격 (psycopg[binary], langgraph-checkpoint-postgres). [memory] extras 는 SQLite 전용으로 축소의존성 변경
Scaffold_PostgresNodeStrategy 안전장치 — _json_default, connect(timeout=5.0), record_id fail-fast, pool 승급 가이드안정성
.env.examplePOSTGRES_MEMORY_DSN [필수] / POSTGRES_URL [선택] 구조 구분UX
ObservabilityNodeTracer.current_invoke_depth() — nested invoke 감지 공개 API내부 개선
영역변경분류
Flow 템플릿exit 노드 → call_agent_auto(state=state) 1줄로 축약DX 개선
Scaffold envos.getenvRuntimeEnv(source_file=__file__).get(...) 전환 (HTTP/Postgres 템플릿)일관성
a2a-sdk>=0.3.25==0.3.26 (1.0.0 breaking 회귀 차단)안정성
[memory] extrasSQLite 전용으로 의미 재정의 — doctor / cmd_ops 가이드 동기화의존성
영역변경비고
Prompt Template / Input Contracts 편집 UINodeSidePanel 에서 제거. Registry Prompt 바인딩은 AgentEditor UI 에서 유지. graph.jsoninput_contracts 필드는 round-trip 보존code-first 로 전환
Quick Config (HTTP/Postgres 폼)프론트 4파일 + 백엔드 structured_config.py / markers.py / NodeDef.structured_config + 테스트 7개 삭제단일 Code Editor 경로로 수렴 (≈ −1000 LOC)
영역버그
Flow / agent-general 스트리밍_agent_is_stream_safe gate 가 신뢰 타입(LangGraphAgent / GraphInvocationAdapter / GuardrailRuntimeAdapter)을 차단해 message/stream 이 invoke 로 강등되던 버그. 해당 타입에 __llamon_bypass_runtime_adapter_check__ = True 마커 추가
call_llm 이중 토큰 emiton_text_chunk 미지정 시 자동 writer 호출 제거. custom + messages 채널 중복 발행으로 artifact 2배 누적되던 버그 수정
Stream 경로 invoke 중복 폴백_extract_stream_text 가 llamon-20b chunk 포맷(additional_kwargs.reasoning_content 등) 놓쳐 emitted_any=False 로 invoke 폴백이 가동, 동일 프롬프트가 stream+invoke 로 2회 생성되던 문제. 추출 범위 확장
Stream trace name 덮어쓰기nested 호출에서 inner agent 의 .stream()trace_invoke_span(is_root=True) 를 하드코딩해 부모 trace name 을 {node}.stream 으로 덮어쓰던 버그. is_root=(current_invoke_depth() == 0) 규칙으로 정렬

A2A 에러 처리 페이지에 단독으로 정리돼 있습니다. 주요 API:

from llamon_agent.core.errors import (
ErrorCode, # 분기용 고정 enum 8개
raise_application_error, # 도메인 특화 reason + extras 선언
LlamonApplicationError, # 매핑 우회 커스텀 예외
# Pydantic 모델 + 팩토리 (SDK 내부용)
ProtocolErrorData, ApplicationErrorData,
make_protocol_error_data, make_application_error_data,
application_error_to_parts,
python_exc_to_error_code,
)

클라이언트팀 영향: -32603 Internal Error 로 뭉뚱그려지던 내부 예외가 result.status.state === "failed" 로 내려옵니다. error 필드만 검사하던 파싱 로직은 Application-level 실패를 놓치므로 toError(resp) normalizer 적용 필요.


영역변경분류
ReAct envMAX_RETRYREACT_MAX_ITERATIONSBreaking
flow 스트리밍마지막 노드만 토큰 출력동작 변경
config.py 역할3계층 모델 정립 (node-local / config.py / .env)DX 개선
Studio 승급·강등공유 env 감지 → inline 배너 + diff 적용신규 기능
write_configAST-merge 전환 — Agent Editor 저장 시 사용자 상수 보존동작 변경 (안전해짐)
Structured 어댑터SchemaValidatedRuntimeAdapter 신설신규 API (권장)
MCP 호출@deterministic_tool 신설신규 API
ObservabilityTraceBackend 추상화, HTTP ingestion 기본내부 개선
Langfuseobservation type 매핑 강화UI 표시 변경
HTTP 노드HttpApiBackend 배치 큐 전환처리량 개선
MemoryMEMORY_WINDOW_SIZE 설정 추가신규 옵션
Guardrail병렬 평가, max_token 제한성능 개선
CLI--no-wheelhouse, restore-online 보정옵션 정리
Kafka핫-리로드 안정화, stale timeout안정성

Terminal window
# 모든 에이전트/플로우 디렉토리에서 한 번에 치환
sed -i '' 's/^MAX_RETRY=/REACT_MAX_ITERATIONS=/' .env .env.example
항목v0.1.xv0.2
.envMAX_RETRYREACT_MAX_ITERATIONS
미변경 시동작서버 시작 실패
Python API ExtensionConfig(max_retry=...)유지유지
agent-card.jsonmaxRetry 필드표시표시

배경: 레포의 docs/runtime/react-recursion.md.


M2. flow 스트리밍 — 마지막 노드만 토큰 출력

섹션 제목: “M2. flow 스트리밍 — 마지막 노드만 토큰 출력”

message/stream 응답에 토큰을 흘릴 수 있는 노드는 END에 연결된 마지막 노드 하나뿐입니다. 그 외 중간 노드는 결과를 state에 담아 다음 노드로 넘기기만 합니다.

[client] --message/stream--> [agent_a] --output--> [agent_b] --output--> [final] --토큰 스트림--> [client]
(sync) (sync) (END에 연결, 스트리밍 가능)
  • v0.1.x에서 중간 노드가 get_stream_writer()로 토큰을 직접 푸시하던 flow → 이 토큰들이 사용자 화면에 더 이상 안 나옵니다
  • 마지막 노드 1개만 LLM 응답을 보내는 flow → 영향 없음

graph.py에서 END에 연결된 노드를 찾으세요.

builder.edge("agent_b", "final")
builder.edge("final", END) # ← "final"이 exit 노드. 여기서만 스트림 가능

마지막 노드에서 스트림 요청 여부를 확인하고 토큰을 출력합니다.

app/nodes.py — 마지막 노드
from llamon_agent import AIMessage, get_stream_writer
async def final_node(state, *, agent_url: str) -> dict:
is_streaming = state.get("metadata", {}).get("is_stream_request")
if is_streaming:
writer = get_stream_writer()
full_text = ""
async for chunk in call_agent_stream(agent_url, build_agent_context(state)):
writer(chunk)
full_text += chunk
return {"messages": [AIMessage(content=full_text)], "output": full_text}
# 비스트림 호출은 평소대로
output = await call_agent(agent_url, build_agent_context(state))
return {"messages": [AIMessage(content=output)], "output": output}

전체 패턴: 플로우 공통 패턴 → 스트리밍 규칙.


M3. config.py 3계층 모델 + Studio 승급·강등 (선택, 마이그레이션 불필요)

섹션 제목: “M3. config.py 3계층 모델 + Studio 승급·강등 (선택, 마이그레이션 불필요)”

v0.2 부터 환경 설정값의 위치를 수명주기 기준으로 구분해 둡니다.

계층위치담는 것
노드 수명nodes.py 상단 RuntimeEnv(source_file=__file__)해당 노드 하나만 쓰는 env 값
프로젝트 수명app/config.py여러 노드가 공유하는 이름·기본값 + 배선 정보
배포 수명.env배포 환경별 값 + secrets (단일 진입점)

원칙: config.py 는 공유되는 이름·기본값만. secrets·환경 종속 값은 항상 .envRuntimeEnv 경유로 읽으세요.

Studio 가 노드 코드를 AST 로 분석해 다음을 inline 배너로 제안합니다:

  • 승급: 2+ 개 노드에서 같은 env 키가 동일 default·타입으로 쓰이면 config.py 로 이동 제안
  • 강등: config.py 상수가 1개 노드에서만 참조되면 node-local 로 되돌리기 제안
  • 충돌: 같은 키가 다른 default 로 여러 곳에 있으면 값 통일 안내
  • 보안 휴리스틱: SECRET, KEY, TOKEN, PASSWORD, DSN, URL, PASS 키워드를 포함한 키는 자동 승급 후보에서 제외 — .env 전용 대상
  • 와이어링 보호: graph.py / main.py 에서만 참조되는 상수는 demote 하지 않음 (apply 시 import 가 깨지는 것을 방지)

[미리보기] → 실제 unified diff 확인 → [적용] 으로 파일 일괄 수정. 중간 실패 시 FileRestoreTransaction 이 자동 롤백합니다.

write_config AST-merge — 기존 상수 보존

섹션 제목: “write_config AST-merge — 기존 상수 보존”

이전 버전에서는 Studio Agent Editor 저장이 config.py 를 통째로 재작성해 AGENT_A_ID 같은 Registry Agent ID 상수, 사용자 수동 상수, 주석 블록이 소실될 수 있었습니다. v0.2 부터는 AST-merge 로 build_extension() 함수만 교체하고 나머지 모든 내용 (상수, 주석, 커스텀 import, 승급한 공유 env 상수) 이 보존됩니다.

  • 기존 프로젝트는 수정 불필요 — 기존 config.py 는 그대로 동작합니다.
  • 새로 생성되는 config.py 상단에 3계층 원칙 주석이 자동 삽입됩니다.
  • config.py 에 secret 이 박혀 있다면 .env 로 옮기는 것을 권장합니다 (Studio 가 경고 배너로 안내).

M4. Structured 어댑터 → SchemaValidatedRuntimeAdapter (선택, 권장)

섹션 제목: “M4. Structured 어댑터 → SchemaValidatedRuntimeAdapter (선택, 권장)”

extract_payload / build_summary를 직접 다루던 코드를 Pydantic 스키마 1개로 줄일 수 있습니다.

Before — StructuredOutputAgent (수작업)

섹션 제목: “Before — StructuredOutputAgent (수작업)”
app/runtime_adapter.py
from llamon_agent import StructuredOutputAgent
class MyAgent(StructuredOutputAgent):
def extract_payload(self, text, data):
payload = super().extract_payload(text, data)
intent = str(payload.get("intent", "")).strip()
if intent not in ("simple_query", "document_verification"):
intent = "unclassified"
confidence = float(payload.get("confidence", 0.0))
confidence = max(0.0, min(1.0, confidence))
return {"intentType": intent, "confidence": confidence,
"originalQuery": payload.get("originalQuery", "")}
def build_summary(self, payload):
return f"질의를 {payload['intentType']}로 분류했습니다 (신뢰도 {payload['confidence']})"

After — SchemaValidatedRuntimeAdapter[PayloadT]

섹션 제목: “After — SchemaValidatedRuntimeAdapter[PayloadT]”
app/runtime_adapter.py
from pydantic import BaseModel, Field
from typing import Literal
from llamon_agent import SchemaValidatedRuntimeAdapter
class IntentPayload(BaseModel):
intentType: Literal["simple_query", "document_verification", "unclassified"]
confidence: float = Field(ge=0, le=1, default=0.0)
originalQuery: str = ""
class MyAgent(SchemaValidatedRuntimeAdapter[IntentPayload]):
payload_schema = IntentPayload
def apply_business_rules(self, payload, *, query, a2a_files, **_):
if a2a_files and payload.intentType != "document_verification":
payload.intentType = "document_verification"
payload.confidence = max(payload.confidence, 0.6)
return payload
def format_summary(self, payload):
return f"질의를 {payload.intentType}로 분류했습니다 (신뢰도 {payload.confidence})"
항목StructuredOutputAgentSchemaValidatedRuntimeAdapter
JSON 파싱수작업자동
타입 캐스팅 / 범위 검증수작업자동 (Pydantic)
검증 실패 처리수작업on_validation_error() 훅 (기본: 안전 안내 응답)
비즈니스 룰 위치extract_payloadapply_business_rules() (선택, 기본 no-op)
summarybuild_summary 필수format_summary (기본: payload의 summary/output_text/message 자동 탐색)
코드 양150370줄2030줄

위의 Before 코드는 일반적인 패턴을 단순화한 illustrative 예시입니다. 실제 프로젝트에서는 추가 보정·로깅 로직이 더 들어가지만, 마이그레이션 작업의 큰 그림(수작업 → 스키마 위임)은 동일합니다.

전체 가이드 + on_validation_error 예시: Registry 기반 에이전트 → SchemaValidated.


M5. MCP 호출 — @deterministic_tool (선택)

섹션 제목: “M5. MCP 호출 — @deterministic_tool (선택)”

ReAct 루프(LLM 자율 판단) 전에 코드로 확정 호출해야 할 때 사용합니다 (규제·민감 도메인 등).

from llamon_agent import deterministic_tool, DeterministicContext
@deterministic_tool(mcp_id="bank-service")
def route_bank(ctx: DeterministicContext) -> dict | None:
if "예금" in ctx.query:
return {"tool_name": "get_deposit_rate", "params": {"bank_code": "004"}}
return None # 매치 안 됨 → ReAct 폴백

자세한 사용법: 확정 MCP 호출 (deterministic_tool).


명령변경
prepare-offline--no-wheelhouse 추가 (wheelhouse 단계 스킵)
restore-online온라인 Dockerfile 복원 안정화
packagedist/ 자체는 아카이브에서 제외

폐쇄망 흐름은 로컬 실행/점검 + 폐쇄망 준비 참조.


API임포트가이드
SchemaValidatedRuntimeAdapter[PayloadT]from llamon_agent import SchemaValidatedRuntimeAdapter에이전트 → SchemaValidated
deterministic_tool, DeterministicContextfrom llamon_agent import deterministic_tool, DeterministicContext확정 MCP 호출

  • Breaking: .envMAX_RETRYREACT_MAX_ITERATIONS (즉시 수정)
  • 유지: Python API ExtensionConfig(max_retry=...) (인자명 그대로)
  • 유지: agent-card.jsonmaxRetry 필드
  • 유지: StructuredOutputAgent 베이스 (SchemaValidatedRuntimeAdapter로 옮길지는 선택)
  • 유지: 기존 flow scaffold (스트리밍 동작 향상)
  • 주의: Langfuse trace UI에서 일부 항목 분류가 더 정확해져 기존 대시보드 필터 재확인 권장