<a id="session-construction"></a>
# Session 실행 루프

상위 경로: [Norma 시스템 지도](../README.md#system-map) → [기능 지도](../features/README.md#feature-map) → Session 실행

`agentcore.NewSession`은 host configuration을 stateful 실행 객체로 조립한다. provider와 system prompt를 자동 선택하지 않는다. `Tools == nil`일 때만 `DefaultTools`를 넣고, 비어 있지만 non-nil인 slice는 “기본 도구 없음”을 뜻한다. optional plan, memory, skill, web, todo, ask-user, deferred, background 기능이 같은 registry에 추가된다. 같은 이름을 다시 등록하면 오류가 아니라 뒤의 tool이 교체한다. [Session 구성 근거](evidence:agentcore-newsession) [registry 근거](evidence:tool-registry)

| 입력 묶음 | 조립 결과 | 판단을 바꾸는 조건 |
|---|---|---|
| Provider, prompts, model options | model request template | provider nil/오류는 construction 때 모두 검증되지 않음 |
| Tools, permission, hooks | registry와 action pipeline | nil Tools만 defaults; plan mode는 live controller를 사용 |
| Compaction / Compactor | 하나의 context manager | custom `Compactor`가 있으면 built-in 설정은 warning 뒤 무시 |
| Transcript / SessionID | recorder와 resume identity | 빈 ID는 생성되지만 Noa wiring 순서와 별도 확인 필요 |
| budget / settlement | Prompt별 loop limits | MaxDuration은 turn/tool 경계 중심이며 model hard deadline이 아님 |
| WorkingDir / BashEnv / output | tool execution context | 편의 설정이며 sandbox나 credential broker가 아님 |

Session은 concurrent `Prompt`를 지원하지 않는다. messages, usage, plan controller와 writer 전체를 보호하는 Prompt-level lock이 없으므로 병렬 task는 독립 Session과 run identity를 사용해야 한다.

<a id="prompt-lifecycle"></a>
## Prompt 생명주기

```mermaid
sequenceDiagram
  participant Host
  participant Session
  participant Harness
  participant View as Context view
  participant Model
  participant Tools

  Host->>Session: Prompt(ctx, input)
  Session->>Session: memory/hook context 합성
  Session->>Session: user message + transcript append
  Session->>Harness: Query(message snapshot, options)
  loop terminal 전
    Harness->>View: Pre/View(messages)
    View-->>Harness: provider-visible messages
    Harness->>Model: Stream 또는 Complete
    Model-->>Harness: text/thinking/tool/usage
    alt tool_use 있음
      Harness->>Tools: validate/authorize/call
      Tools-->>Harness: tool results
      Harness->>Session: assistant/result recorder events
    else tool_use 없음
      Harness->>Harness: stop/budget/task checks
    end
  end
  Harness-->>Session: KindResult(Terminal)
  Session->>Session: messages/usage commit
  Session-->>Host: terminal event
```

user input에는 optional memory relevance 결과와 `UserPromptSubmit` hook context가 붙은 뒤 history/transcript에 기록된다. 매 Prompt의 날짜와 `SystemReminderFunc` 결과는 임시 첫 user message로 provider view에만 들어가며 conversation/transcript에는 저장되지 않는다. [Prompt 근거](evidence:agentcore-prompt)

`KindResult`를 받은 경우에만 Session이 loop의 최종 messages와 usage로 교체된다. host가 iterator를 중간에 그만두면 이미 시작된 외부 effect가 있을 수 있지만 terminal·Session commit은 없다. [event 계약](evidence:harness-event)

<a id="stream-and-tool-loop"></a>
## Stream과 tool 반복

streaming provider에서는 완성된 `tool_use` block이 도착하자마자 scheduler 후보가 된다. model이 같은 response의 뒤쪽 token을 생성하는 동안 concurrency-safe tool이 실행될 수 있다. response가 끝난 뒤 assistant message와 tool results를 user message 한 개로 묶고 다음 model turn으로 간다. non-streaming provider도 response 조립 뒤 같은 종류의 host event를 낸다. [streaming 근거](evidence:harness-streaming)

| 단계 | 입력 → 출력 | 실패 후 상태 |
|---|---|---|
| view | stored messages → request messages | compactor 오류/recovery 분기 |
| provider | request → normalized stream/full response | pre-stream retry 또는 terminal error |
| accumulation | deltas → assistant blocks, stop reason, usage | malformed tool JSON은 빈 object로 떨어질 수 있음 |
| tool execution | tool uses → ordered results | deny/error도 synthetic result로 pair |
| record | assistant + user tool-result → history | recorder failure가 terminal로 자동 승격되지 않음 |
| continue/stop | stop·budget·notifications → next request/terminal | 이유별 continuation은 main tool-turn count와 다름 |

stream error나 consumer 중단 전에 이미 tool goroutine이 시작될 수 있다. 일부 경로에서는 외부 effect가 생겼지만 assistant/tool-result pair와 transcript가 남지 않는 orphan action 가능성이 있다. 이는 정적 흐름에서 확인한 경계이며 별도 race 재현은 하지 않았다.

<a id="scheduler"></a>
## Scheduler와 동시성

한 response의 tool calls는 도착 순서를 보존하되 `IsConcurrencySafe(input)`으로 실행 방식을 나눈다.

1. safe call은 semaphore 안에서 병렬 시작한다.
2. exclusive call은 앞선 safe calls가 끝날 때까지 기다린 뒤 단독 실행한다.
3. exclusive call 뒤의 safe call은 그 exclusive가 끝난 다음 시작한다.
4. 결과 event와 final tool-result 배열은 model arrival order를 유지한다.
5. 기본 `MaxConcurrency`는 10이다.

`ReadOnly`는 permission metadata이고 `Concurrent`는 scheduler metadata다. 둘은 같은 값이 아니다. host callback, registry가 가리키는 mutable tool instance와 공유 filesystem에 대한 thread safety는 Norma가 만들지 않는다. [scheduler 근거](evidence:harness-streaming) [tool 계약](evidence:tool-contract)

<a id="termination-and-settlement"></a>
## 종료, budget과 settlement

`MaxTurns`는 model call 전체가 아니라 **main phase에서 tool을 사용한 turn 수**를 센다. reactive retry, max-output recovery, stop-hook continuation, token-budget nudge와 task notification에 따른 model call은 모두 같은 방식으로 세지지 않는다. 내부 iteration 방어 한계는 10,000이다. [loop 근거](evidence:harness-query)

`MaxDuration`은 시작 시각을 기준으로 tool context에 deadline을 주고 turn 경계에서 확인한다. provider stream과 compaction은 parent context를 사용하므로 느린 model이 duration을 넘긴 뒤 tool 없는 응답을 내면 `completed`가 될 수 있다. hard wall-clock이 필요하면 caller가 parent context deadline을 설정한다.

budget에 닿고 `Settlement`가 있으면 checkpoint prompt를 넣고 제한된 wrap-up phase를 실행한다. 최종 reason은 원래 `max_turns` 또는 `timeout`을 유지한다. `DisabledTools`는 provider schema에서 숨길 뿐 registry execution을 금지하지 않는다.

Stop hook의 결과는 서로 다르다.

| hook 결과 | loop 행동 |
|---|---|
| `PreventContinuation` | `stop_hook_prevented` terminal |
| block + context | context를 넣고 continuation |
| allow/no result | token budget, task notification을 이어 검사 |
| tool-use turn 이후 | stop re-entry flag가 초기화될 수 있음 |

host가 완료 판정에 보존해야 할 최소 값은 terminal reason/error/turns/usage, 최종 messages와 text, 시작된 action의 durable ID, 미결 background/process 상태다. [완료 의미](../README.md#completion-boundary)와 [event 계약](../contracts/README.md#event-contract)을 함께 본다.
