콘텐츠로 이동

변수, 표현식, 트리거

${...} 및 ${{ ... }} 보간 시스템, 크론 및 엔티티 이벤트 트리거, 그리고 다중 실행 연속성 패턴.

워크플로우 YAML은 대부분 정적이지만, 단계 간에 흐르는 값은 그렇지 않습니다. Revka는 런타임 데이터를 문자열 필드에 연결하는 두 가지 보간 시스템과, 워크플로우를 자동으로 실행하는 두 가지 트리거 유형을 제공합니다. 이를 조합하면 상태를 하드코딩하지 않고도 한 실행이 다음 실행으로 이어지도록 만들 수 있습니다.

이 페이지에서는 ${...} 변수 보간, ${{ ... }} 표현식, cronentity-event 트리거 블록, input_map 자동 매핑, 그리고 이 모든 것을 하나로 엮는 다중 실행 연속성 패턴을 설명합니다. 상위 스키마는 워크플로우 YAML 레퍼런스를, 각 단계 본문은 단계 유형 레퍼런스를 참고하십시오.

단계의 대부분 사용자 작성 문자열 필드는 ${...} 보간을 지원합니다. 변수는 실행 시점에 현재 워크플로우 상태를 기준으로 확인됩니다. 보간은 에이전트 프롬프트, 셸 명령, Python 인수, 알림 메시지, output 템플릿, 엔티티 게시 필드, resolvekind/tag/name_pattern/space, 조건부 조건, 브랜치 값, goto 가드, 이메일 필드에서 동작합니다.

${...} 조회는 항상 텍스트로 렌더링됩니다.

agent:
prompt: |
Topic: ${inputs.topic}
Prior summary: ${resolve_prior.output_data.summary}
Run: ${run_id}
참조확인되는 값
${inputs.name}워크플로우 입력 파라미터
${trigger.entity_kref}트리거한 엔티티의 kref
${trigger.entity_name}트리거한 엔티티의 이름
${trigger.entity_kind}트리거한 엔티티의 kind
${trigger.tag}트리거한 리비전 태그
${trigger.revision_kref}트리거한 리비전의 kref
${trigger.metadata.key}트리거한 엔티티의 메타데이터 필드
${step_id.output}단계의 텍스트 출력
${step_id.status}completed | failed | running | skipped
${step_id.error}실패한 단계의 오류 메시지
${step_id.output_data.key}단계의 구조화 출력 필드
${step_id.files}단계가 처리한 파일 목록(쉼표 구분)
${step_id.agent_id}에이전트 ID (에이전트 단계)
${loop.iteration}현재 goto 루프 반복 횟수
${env.VAR}환경 변수
${run_id}워크플로우 실행 UUID

첫 번째 실행 패턴이 실패하지 않도록 보간은 의도적으로 너그럽게 동작합니다.

  • 확인되지 않은 ${step.output_data.key}""를 반환합니다 — 해당 단계가 아직 실행되지 않았거나, 키가 없거나, resolve 단계가 found: false를 반환한 경우입니다.
  • 그 외 확인되지 않은 ${...} 참조는 리터럴 그대로 남아 실행 진단에 표시되므로, 오타를 쉽게 발견할 수 있습니다.

첫 번째 실행용 resolve 단계에는 fail_if_missing: false를 함께 사용하고, 빈 resolved 필드를 허용하는 프롬프트를 작성하십시오. 아래 연속성 패턴을 참고하십시오.

${{ ... }}는 타입이 있는 표현식 평가기로, conditional 단계의 조건에 사용되는 것과 동일한 안전한 평가기입니다. 단순한 값 조회가 아니라 함수, 산술, 비교, 멤버십 검사, 폴백 로직이 필요할 때 사용하십시오.

${{ ... }} 내부에서는 각 조회를 ${...}로 감싸지 않고 위의 네임스페이스를 직접 참조합니다.

resolve:
name_pattern: "daily-${{ lower(inputs.team) }}-*"
space: "Revka/${{ lower(inputs.team) }}/Reports"
outputs:
next_episode: "${{ int(resolve_cursor.output_data.episode_number) + 1 }}"
publish_ready: "${{ review.output_data.score >= 0.8 }}"
기능예시
비교a == b, a != b, score >= 0.8
불리언 논리ok and not blocked, status == 'done' or retry_count > 0
멤버십'approve' in lower(review.output), review.output contains 'APPROVED'
산술int(count) + 1, price * quantity
문자열 헬퍼lower(x), upper(x), str(x), format(score, '.2f'), pad(n, 3)
타입 헬퍼int(x), float(x), bool(x), len(x)
동등 헬퍼eq(a, b)
리스트 / 범위range(1, int(inputs.count) + 1)

동일한 연산자가 conditional 브랜치, goto 가드, parallel/map_reduce 조인 로직에서도 사용됩니다. 이 필드들은 ${{ }} 래퍼 없이 표현식을 직접 받습니다. 예: condition: "review.output_data.score >= 0.8".

워크플로우는 기본적으로 수동 실행됩니다. 자동 실행을 위해서는 최상위에 triggers: 목록을 추가하십시오. 두 가지 트리거 유형은 같은 목록에 공존할 수 있습니다.

triggers:
- cron: "0 9 * * 1" # every Monday 09:00
timezone: "America/Los_Angeles" # optional IANA timezone (alias: tz)
필드타입 / 기본값의미
croncrontab 문자열 (필수)5-필드 crontab, 또는 6/7-필드 cron-crate 형식
timezoneIANA 문자열 (선택)스케줄 평가에 사용할 타임존; tz를 별칭으로 사용 가능

크론 트리거가 있는 워크플로우를 Kumiho에 저장하면(예: 대시보드에서), Revka가 크론 저장소에 스케줄된 작업을 자동으로 등록합니다. 스케줄된 시각에 스케줄러는 POST /api/workflows/run/{name}을 직접 호출합니다.

  • 5-필드 표현식은 초(seconds) 필드가 자동으로 앞에 추가되며, 요일 값은 내부 cron crate의 규칙(1 = 일요일)에 맞게 정규화됩니다(0/7 = 일요일).
  • 크론 작업은 워크플로우의 생성, 업데이트, 삭제, 사용 중단 시마다 동기화됩니다. 워크플로우를 사용 중단하거나 삭제하면 연관된 크론 작업도 제거됩니다.
  • 크론 전용 트리거에는 on_kind/on_tag가 필요하지 않습니다 — 이 필드들은 엔티티 트리거에만 적용됩니다.

엔티티 트리거는 Kumiho에서 revision.tagged 이벤트를 감시합니다. 상위 output 단계가 규칙에 맞는 엔티티를 게시하면 하위 워크플로우가 자동으로 실행됩니다. 이를 통해 워크플로우를 체이닝할 수 있습니다.

triggers:
- on_kind: "qs-arc-plan" # entity kind (required)
on_tag: "ready" # revision tag (default: "ready")
on_name_pattern: "qs-*" # optional glob on entity name
on_space: "Revka/WorkflowOutputs/QuantumSoul" # optional space-path prefix
input_map: # map trigger data → inputs
arc_kref: "${trigger.entity_kref}"
arc_name: "${trigger.metadata.arc_name}"

필터는 누적(AND) 방식으로 적용됩니다 — 지정된 모든 필터가 일치해야 합니다.

필드매칭 동작
on_kind엔티티 kind의 정확한 일치. 엔티티 트리거에 필수.
on_tag리비전 태그의 정확한 일치. 생략 시 기본값은 ready.
on_name_pattern엔티티 이름에 대한 선택적 글로브 패턴, 예: daily-*.
on_space선택적 space-path 접두사, 예: Revka/Reports.

input_map은 트리거 데이터를 하위 워크플로우의 입력으로 변환합니다. 각 키는 입력 이름이고, 각 값은 ${trigger.*} 네임스페이스를 참조하는 ${...} 표현식입니다.

input_map을 생략하거나(또는 필수 입력이 매핑되지 않은 경우), Revka는 자동 매핑을 시도합니다. 트리거한 엔티티의 메타데이터 키가 필수 워크플로우 입력 이름과 일치하면 해당 값이 자동으로 매핑됩니다. 게시하는 output 단계에 metadata_target: item을 설정하면 해당 메타데이터 키를 자동 매핑에 사용할 수 있습니다.

따라서 entity_metadata.arc_name을 포함해 게시하는 상위 단계는, 명시적인 input_map 없이도 하위 arc_name 입력을 충족시킵니다. input_map은 이름이 다르거나 entity_kref처럼 메타데이터가 아닌 필드를 매핑할 때만 명시적으로 사용하십시오.

quantum-soul-arc-room
└─ output step publishes: kind=qs-arc-plan, tag=ready
└─ event listener matches the trigger on quantum-soul-episode-room
└─ quantum-soul-episode-room launches with arc context
└─ output step publishes: kind=qs-episode-final, tag=published
└─ the next arc-room run resolves this as its cursor

이 패턴은 이전 실행 결과를 기반으로 다음 실행을 이어가는 워크플로우를 위한 정규 패턴입니다. 상태를 하드코딩하지 않고도 지난 실행이 무엇을 생성했는지 파악해야 하는 주간 작업 등에 활용할 수 있습니다.

이 패턴은 세 가지 요소로 구성됩니다. 이전 출력을 찾는 resolve 단계(첫 번째 실행에서는 비어 있음), 첫 번째 실행의 기본값을 제공하는 시드 inputs, 그리고 다음 실행이 가져올 새 엔티티를 게시하는 output 단계입니다.

inputs:
- name: arc_name
default: "awakening-arc-1" # seed for the first run
description: Auto-resolved on subsequent runs
steps:
# 1. Try to find the previous output (empty on first run)
- id: resolve_prior
type: resolve
resolve:
kind: "qs-arc-plan"
tag: "ready"
fail_if_missing: false # don't fail when nothing exists yet
# 2. Agent uses resolved data OR the seed inputs
- id: plan
type: agent
depends_on: [resolve_prior]
agent:
prompt: |
## Auto-resolved from last run (empty on first run)
Previous arc: ${resolve_prior.output_data.arc_name}
Episode range: ${resolve_prior.output_data.episode_range}
Continuity: ${resolve_prior.output_data.continuity_context}
## Seed inputs (use when auto-resolved is empty)
Arc name: ${inputs.arc_name}
Use auto-resolved values when available; fall back to seeds on first run.
# 3. Publish an entity for the next run to find
- id: output
type: output
depends_on: [plan]
output:
template: "${plan.output}"
entity_name: "qs-arc-${inputs.arc_name}"
entity_kind: "qs-arc-plan"
entity_tag: "ready"
entity_metadata:
arc_name: "${inputs.arc_name}"
episode_range: "1-8"
continuity_context: "${plan.output}"

실행 간 동작 방식:

  • 첫 번째 실행resolve_prior.output_data.foundfalse이고 resolved 필드는 ""로 렌더링됩니다. 에이전트는 시드 입력으로 폴백하고, output 단계가 첫 번째 엔티티를 게시합니다.
  • 두 번째 실행resolve_prior가 첫 번째 실행의 엔티티를 찾습니다. 에이전트는 resolved 연속성 컨텍스트를 사용하고, output은 세 번째 실행을 위한 새 엔티티를 게시합니다. 이후 반복됩니다.
  1. 비어 있을 수 있는 resolve 단계에는 항상 fail_if_missing: false를 설정하십시오.

  2. 첫 번째 실행을 위해 inputs에 적절한 default 값을 지정하십시오.

  3. 프롬프트는 자동 resolved 섹션과 시드 입력 섹션 모두를 포함하도록 구성하고, resolved 값을 우선하도록 에이전트에게 지시하십시오.

  4. 다음 실행에 필요한 모든 정보를 entity_metadata에 저장하십시오.

  5. 게시 단계의 output.metadata_target과 읽기 단계의 resolve.metadata_source를 맞추십시오. metadata_target: item은 트리거 자동 매핑을 활성화하며, metadata_target: revisionmetadata_source를 설정하지 않아도 resolve 단계가 메타데이터를 읽을 수 있게 합니다(metadata_source의 기본값은 revision).

  6. output 단계와 resolve 단계 간에 entity_kind + entity_tag가 일치하도록 하여 검색이 실제로 엔티티를 찾을 수 있게 하십시오.