ModelAgents module
Invocation
Invocation
Tenanted through its own client_id rather than through a relation, so the Doctrine filter
binds on every query — a row holds the full transcript (every prompt, tool result and decision),
which is customer content, and no read should depend on the caller remembering to scope itself.
The own-column form matters because neither relation is a reliable owner: agentInstall is
nullable with ON DELETE SET NULL, and batchAction reaches a Sited Batch only through an
untenanted hop. client_id is NOT NULL and is autofilled from the AuthSite the batch runs under.
A model in the Agents module, with 29 members for templates, 28 API properties and 31 members for admin templates.
Templates view
Properties 29
Take no arguments.
-
#
getDurationSeconds() -
?float - Duration of the invocation in seconds, or null while it is still running.
-
#
getDecisionSummaryHtml() -
string - Render the LLM-authored decision summary as HTML. The stored summary is markdown produced by the agent, so the admin detail view gets a nicely-formatted block rather than raw markdown source. Parsedown safe mode is on because the content is model-generated and therefore untrusted.
-
#
getTranscriptTurns() -
array - Flatten the provider-neutral transcript into display-friendly turns for the admin detail view. The stored transcript is the verbatim messages array (role + neutral parts, each part a text / tool_call / tool_result map). Templates should not reverse-engineer that shape, so this returns one row per visible turn: [ ['index' => int, 'kind' => 'user'|'assistant'|'tool_call'|'tool_result', 'call' => int, 'title' => string, 'body' => string], ... ] Turns are in stored order and
indexis a 1-based sequence over the displayed rows, so the reader can cite a position unambiguously.callis a 1-based number shared by a tool_call and the tool_result that answers it (paired on the provider's tool-call id), and is 0 for non-tool turns — a result does NOT always follow its call adjacently, because the loop dispatches a whole batch of calls before returning any of their results. -
#
getTranscriptPrompt() -
string - The opening user message the run was given. There is no prompt column — the composed user message survives only as the first text part of the transcript, so a run that failed before reaching the provider (transcript
[]) has none. -
#
getTranscriptSteps() -
array - The run as an ordered list of steps, one row per tool call. Where
getTranscriptTurns()returns the transcript part-by-part, this joins each tool_call to the tool_result answering it — the two are rarely adjacent, because the loop dispatches a whole batch of calls before any result comes back — so the reader sees a call and its outcome as one row. Rows are either a tool call: ['kind' => 'step', 'n' => int, 'tool' => string, 'ok' => bool, 'status' => string, 'ms' => int|null, 'summary' => string, 'resultSize' => string, 'resultLines' => int, 'args' => string, 'result' => string, 'answered' => bool] or the model's narration between two calls: ['kind' => 'reasoning', 'text' => string] The framing parts are omitted: the opening user message and the closing assistant message are rendered as their own pinned cards (seegetTranscriptPrompt()andgetDecisionSummaryHtml()), so including them here would duplicate them.msis null andokis inferred from the result text for turns recorded before the loop stored those facts explicitly.answeredis false when no result was ever recorded for the call — the run died mid-turn. -
#
getTranscriptStats() -
array - Headline counts for the transcript view.
totalMsis the summed wall-clock time of the tool calls — not the run duration, which is dominated by provider latency — and is null when no step carries a timing (every pre-timing invocation). -
#
getId() -
?int -
#
getLibraryAgentSlug() -
?string -
#
getPromptContentHash() -
?string -
#
getProvider() -
?string -
#
getModel() -
?string -
#
getRequestedTier() -
?string -
#
getStartedAt() -
?DateTime -
#
getEndedAt() -
?DateTime -
#
getTotalInputTokens() -
?int -
#
getTotalOutputTokens() -
?int -
#
getTotalCostUsd() -
?string -
#
getDecisionSummary() -
?string -
#
getTerminationReason() -
?string -
#
getTranscript() -
?array -
#
getStructuredResult() -
?array -
#
getRecommendationsProduced() -
?int -
#
getBatchAction() -
?BatchAction -
#
getReplayedFrom() -
?Invocation - The original invocation this row is a cost-free replay of, or null for a first-class invocation. Set by the re-run replay path. The FK is SET NULL on delete so removing the original never deletes its replays.
-
#
isHierarchicalModel()Not in API & Jobs -
bool - Check whether a model is a hierarchical model, i.e. can have children
No members match the filter.
API & Jobs view
API & JobsEach property is a key in REST API responses and job payloads. Its name is the template getter without get, is or has. Methods that need arguments are not available here.
Properties 28
Read-only values on the record.
-
#
decisionSummaryHtml -
string - Render the LLM-authored decision summary as HTML. The stored summary is markdown produced by the agent, so the admin detail view gets a nicely-formatted block rather than raw markdown source. Parsedown safe mode is on because the content is model-generated and therefore untrusted.
-
#
transcriptTurns -
array - Flatten the provider-neutral transcript into display-friendly turns for the admin detail view. The stored transcript is the verbatim messages array (role + neutral parts, each part a text / tool_call / tool_result map). Templates should not reverse-engineer that shape, so this returns one row per visible turn: [ ['index' => int, 'kind' => 'user'|'assistant'|'tool_call'|'tool_result', 'call' => int, 'title' => string, 'body' => string], ... ] Turns are in stored order and
indexis a 1-based sequence over the displayed rows, so the reader can cite a position unambiguously.callis a 1-based number shared by a tool_call and the tool_result that answers it (paired on the provider's tool-call id), and is 0 for non-tool turns — a result does NOT always follow its call adjacently, because the loop dispatches a whole batch of calls before returning any of their results. -
#
transcriptPrompt -
string - The opening user message the run was given. There is no prompt column — the composed user message survives only as the first text part of the transcript, so a run that failed before reaching the provider (transcript
[]) has none. -
#
transcriptSteps -
array - The run as an ordered list of steps, one row per tool call. Where
getTranscriptTurns()returns the transcript part-by-part, this joins each tool_call to the tool_result answering it — the two are rarely adjacent, because the loop dispatches a whole batch of calls before any result comes back — so the reader sees a call and its outcome as one row. Rows are either a tool call: ['kind' => 'step', 'n' => int, 'tool' => string, 'ok' => bool, 'status' => string, 'ms' => int|null, 'summary' => string, 'resultSize' => string, 'resultLines' => int, 'args' => string, 'result' => string, 'answered' => bool] or the model's narration between two calls: ['kind' => 'reasoning', 'text' => string] The framing parts are omitted: the opening user message and the closing assistant message are rendered as their own pinned cards (seegetTranscriptPrompt()andgetDecisionSummaryHtml()), so including them here would duplicate them.msis null andokis inferred from the result text for turns recorded before the loop stored those facts explicitly.answeredis false when no result was ever recorded for the call — the run died mid-turn. -
#
transcriptStats -
array - Headline counts for the transcript view.
totalMsis the summed wall-clock time of the tool calls — not the run duration, which is dominated by provider latency — and is null when no step carries a timing (every pre-timing invocation). -
#
id -
?int -
#
libraryAgentSlug -
?string -
#
promptContentHash -
?string -
#
provider -
?string -
#
model -
?string -
#
requestedTier -
?string -
#
startedAt -
?DateTime -
#
endedAt -
?DateTime -
#
totalInputTokens -
?int -
#
totalOutputTokens -
?int -
#
totalCostUsd -
?string -
#
decisionSummary -
?string -
#
terminationReason -
?string -
#
transcript -
?array -
#
structuredResult -
?array -
#
recommendationsProduced -
?int -
#
batchAction -
?BatchAction -
#
replayedFrom -
?Invocation - The original invocation this row is a cost-free replay of, or null for a first-class invocation. Set by the re-run replay path. The FK is SET NULL on delete so removing the original never deletes its replays.
No members match the filter.
Admin view
AdminAvailable in cdna-admin templates. Copy an admin template into your site repository to change how this record is edited.
Properties 31
Take no arguments.
-
#
getDurationSeconds() -
?float - Duration of the invocation in seconds, or null while it is still running.
-
#
getDecisionSummaryHtml() -
string - Render the LLM-authored decision summary as HTML. The stored summary is markdown produced by the agent, so the admin detail view gets a nicely-formatted block rather than raw markdown source. Parsedown safe mode is on because the content is model-generated and therefore untrusted.
-
#
getTranscriptTurns() -
array - Flatten the provider-neutral transcript into display-friendly turns for the admin detail view. The stored transcript is the verbatim messages array (role + neutral parts, each part a text / tool_call / tool_result map). Templates should not reverse-engineer that shape, so this returns one row per visible turn: [ ['index' => int, 'kind' => 'user'|'assistant'|'tool_call'|'tool_result', 'call' => int, 'title' => string, 'body' => string], ... ] Turns are in stored order and
indexis a 1-based sequence over the displayed rows, so the reader can cite a position unambiguously.callis a 1-based number shared by a tool_call and the tool_result that answers it (paired on the provider's tool-call id), and is 0 for non-tool turns — a result does NOT always follow its call adjacently, because the loop dispatches a whole batch of calls before returning any of their results. -
#
getTranscriptPrompt() -
string - The opening user message the run was given. There is no prompt column — the composed user message survives only as the first text part of the transcript, so a run that failed before reaching the provider (transcript
[]) has none. -
#
getTranscriptSteps() -
array - The run as an ordered list of steps, one row per tool call. Where
getTranscriptTurns()returns the transcript part-by-part, this joins each tool_call to the tool_result answering it — the two are rarely adjacent, because the loop dispatches a whole batch of calls before any result comes back — so the reader sees a call and its outcome as one row. Rows are either a tool call: ['kind' => 'step', 'n' => int, 'tool' => string, 'ok' => bool, 'status' => string, 'ms' => int|null, 'summary' => string, 'resultSize' => string, 'resultLines' => int, 'args' => string, 'result' => string, 'answered' => bool] or the model's narration between two calls: ['kind' => 'reasoning', 'text' => string] The framing parts are omitted: the opening user message and the closing assistant message are rendered as their own pinned cards (seegetTranscriptPrompt()andgetDecisionSummaryHtml()), so including them here would duplicate them.msis null andokis inferred from the result text for turns recorded before the loop stored those facts explicitly.answeredis false when no result was ever recorded for the call — the run died mid-turn. -
#
getTranscriptStats() -
array - Headline counts for the transcript view.
totalMsis the summed wall-clock time of the tool calls — not the run duration, which is dominated by provider latency — and is null when no step carries a timing (every pre-timing invocation). -
#
getId() -
?int -
#
getLibraryAgentSlug() -
?string -
#
getPromptContentHash() -
?string -
#
getProvider() -
?string -
#
getModel() -
?string -
#
getRequestedTier() -
?string -
#
getStartedAt() -
?DateTime -
#
getEndedAt() -
?DateTime -
#
getTotalInputTokens() -
?int -
#
getTotalOutputTokens() -
?int -
#
getTotalCostUsd() -
?string -
#
getDecisionSummary() -
?string -
#
getTerminationReason() -
?string -
#
getTranscript() -
?array -
#
getStructuredResult() -
?array -
#
getRecommendationsProduced() -
?int -
#
getBatchAction() -
?BatchAction -
#
getReplayedFrom() -
?Invocation - The original invocation this row is a cost-free replay of, or null for a first-class invocation. Set by the re-run replay path. The FK is SET NULL on delete so removing the original never deletes its replays.
-
#
isHierarchicalModel()Not in API & Jobs -
bool - Check whether a model is a hierarchical model, i.e. can have children
No members match the filter.