@agent-compose/sdk 0.8.6 → 0.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -99,6 +99,8 @@ type DurableAgentMessage = Exclude<AgentMessage, {
99
99
  type: "compaction";
100
100
  } | {
101
101
  type: "subagent_user_message";
102
+ } | {
103
+ type: "model_report";
102
104
  }>;
103
105
  export declare function summarizeAgentMessage(msg: DurableAgentMessage): AgentMessageSummary;
104
106
  export type AgentLifecycleEvent = {
package/dist/client.d.ts CHANGED
@@ -1,16 +1,16 @@
1
1
  import type { ConversationRow, CreateChatInput, ChannelIvyState, DriveSharesView, IvyConnectionsView, ListingPage } from "./types/api-conversations.js";
2
2
  import type { RunEvent } from "./types/events.js";
3
3
  import type { ConversationStreamEvent } from "./types/conversation-stream.js";
4
- import type { InvokeWorkflowOptions, InvokeAndWaitOptions, InvokeResult, StreamRunLogsOptions, InlineWorkflowPayload, InvokeInlineOptions, InvokeInlineAndWaitOptions, RunStatus, ResumePauseOptions, ResumePauseResponse, AnswerSteerOptions, RequestAgentPauseOptions, RequestAgentPauseResponse, SendAgentMessageOptions, SendAgentMessageResponse, RunDetail, RunListEntry, ListRunsOptions, TimelineEvent, RunFundingResponse, RunStepUsageResponse, EventRow, ReportEventInput, ListEventsOptions, ListEventsResult, RunArtifactRow, RunLogLine, ListRunLogsOptions, CancelRunResponse, ListSnapshotsOptions, SnapshotListResponse, SnapshotListEntry, RunSnapshotEntry } from "./types/api-runs.js";
4
+ import type { InvokeWorkflowOptions, InvokeAndWaitOptions, InvokeResult, StreamRunLogsOptions, InlineWorkflowPayload, InvokeInlineOptions, InvokeInlineAndWaitOptions, RunStatus, ResumePauseOptions, ResumePauseResponse, AnswerSteerOptions, RequestAgentPauseOptions, RequestAgentPauseResponse, SendAgentMessageOptions, SendAgentMessageResponse, RunDetail, RunListEntry, ListRunsOptions, TimelineEvent, RunFundingResponse, RunStepUsageResponse, EventRow, ReportEventInput, ListWorkflowActivityOptions, ListWorkflowRunsOptions, WorkflowActivityPage, WorkflowRunsPage, ListEventsOptions, ListEventsResult, RunArtifactRow, RunLogLine, ListRunLogsOptions, CancelRunResponse, ListSnapshotsOptions, SnapshotListResponse, SnapshotListEntry, RunSnapshotEntry } from "./types/api-runs.js";
5
5
  import type { TeamMember, Mention, CreateMentionsInput, ConversationsPage, SessionsPage, ConversationDetail, ConversationThread, CreateCloudSessionInput, CloudSessionCreated, SessionPreview, PreviewOpened, OpenPreviewInput, SessionForked, BackgroundWorkHeld, BackgroundWorkChildDecl, BackgroundWorkStatus, MachineUpsizeOutcome, CreateSessionWaitInput, SessionWait, SessionWaitCreated, SessionWaitList, SessionChangeSet, SessionFilePlane, SessionMergeGated, SessionMergeReport, SessionDiscardReport, SessionChangePreflight, SessionRebaseReport, ReviewSuggestionInput, ReviewNotesPublished, ReviewGitCredential, SendConversationMessageInput, SendConversationMessageResult, ChannelSessionRow, SessionDirectMessageSent, BranchClaimGranted, BranchClaimsReleased, BranchClaimState, ConversationPresenceSnapshot, StreamConversationOptions, AgentListRow, SessionPerfHistoryPage } from "./types/api-conversations.js";
6
6
  import type { ConversationMemberRole, ConversationMember, ArtifactScope, SetScopeGrantsInput, SetTemplateScopeInput } from "./types/api-scopes.js";
7
7
  import type { Project, ProjectUpdate, ProjectsPage, ProjectRole, ProjectMember, ProjectObject, ProjectObjectsPage, ProjectObjectCounts, ProjectAddPreview, AddProjectObjectInput, AddProjectObjectResult, RefreshProjectObjectResult, ProjectStatus, ThreadStatus, MeStatus } from "./types/api-projects.js";
8
8
  import type { RegisterResult, RegisterWorkflowInput, TemplateRow, TemplateDetail, ListTemplatesOptions, SearchFactoryFilesOptions, FactoryFileSearchResult, FactoryFileWriteResult, ListFactoryFilesOptions, FactoryFileListPage, FactoryFileConflict, FactoryFileConflictList, ProjectSecretList, FactoryRow, CreateFactoryInput, UpdateFactoryInput, FactoryPerfSummary, ScheduleRow, CreateScheduleInput, SecretOptions, SetSecretResult, SecretListEntry, SessionSecretEntry, SessionSecretInput, SessionSecretRequestCreated, SessionSecretRequestStatus, SessionSecretRequestSummary, VaultRequestKind, VaultKeyShape, VaultCatalogEntry, RequestedVaultEntry, CreateApiKeyInput, ApiKeyCreated, ListApiKeysOptions, ApiKeyPage, UsageResponse, DriveRepoLink, CreateDriveRepoLinkInput, CreateNativeRepoInput, CreateNativeRepoResult, DriveMountSession, CreateDriveMountSessionInput, ConnectorGrantSummary } from "./types/api-factory.js";
9
9
  import type { ComplianceSession, RequestComplianceSessionInput, ListComplianceSessionsOptions, ComplianceSessionsPage, ListComplianceAccessesOptions, ComplianceAccessesPage } from "./types/api-compliance.js";
10
- export type { RunState, InvokeWorkflowOptions, InvokeAndWaitOptions, InvokeResult, FundingChoice, StreamRunLogsOptions, InlineWorkflowPayload, InvokeInlineOptions, InvokeInlineAndWaitOptions, RunStatus, ResumePauseActor, ResumePauseSuccess, ResumePausePending, ResumePauseResponse, ResumePauseOptions, RequestAgentPauseOptions, AnswerSteerOptions, RequestAgentPauseResponse, SendAgentMessageOptions, SendAgentMessageResponse, RunDetail, RunListEntry, ListRunsOptions, TimelineEvent, FundingLane, RunFundingStamp, RunFundingUsageRow, RunFundingResponse, RunStepUsage, RunStepUsageResponse, EventSubjectType, EventRow, RunArtifactRow, ReportEventInput, ListEventsOptions, ListEventsResult, RunLogLine, ListRunLogsOptions, CancelRunResponse, ListSnapshotsOptions, SnapshotListEntry, SnapshotListResponse, RunSnapshotEntry, } from "./types/api-runs.js";
10
+ export type { RunState, InvokeWorkflowOptions, InvokeAndWaitOptions, InvokeResult, FundingChoice, StreamRunLogsOptions, InlineWorkflowPayload, InvokeInlineOptions, InvokeInlineAndWaitOptions, RunStatus, ResumePauseActor, ResumePauseSuccess, ResumePausePending, ResumePauseResponse, ResumePauseOptions, RequestAgentPauseOptions, AnswerSteerOptions, RequestAgentPauseResponse, SendAgentMessageOptions, SendAgentMessageResponse, RunDetail, RunListEntry, ListRunsOptions, TimelineEvent, RunStartedBy, WorkflowActivityRun, WorkflowActivityHead, ListWorkflowActivityOptions, ListWorkflowRunsOptions, WorkflowActivityPage, WorkflowRunsPage, FundingLane, RunFundingStamp, RunFundingUsageRow, RunFundingResponse, RunStepUsage, RunStepUsageResponse, EventSubjectType, EventRow, RunArtifactRow, ReportEventInput, ListEventsOptions, ListEventsResult, RunLogLine, ListRunLogsOptions, CancelRunResponse, ListSnapshotsOptions, SnapshotListEntry, SnapshotListResponse, RunSnapshotEntry, } from "./types/api-runs.js";
11
11
  export type { TeamMember, Mention, CreateMentionsInput, CreateChatInput, ChannelIvyState, IvyConnection, HiddenIvyConnection, IvyConnectionsView, IvyConnectionScope, ListingPage, DriveShareItem, DriveShare, HiddenDriveShare, DriveSharesView, WorkspaceConnection, WorkspaceConnectionAudienceEntry, WorkspaceConnectionsScopeView, ConversationMessagePart, ConversationRow, ConversationProject, ConversationMessageRow, ConversationsPage, SessionsPage, ConversationDetail, CreateCloudSessionInput, CloudSessionCreated, ConversationThread, ConversationUnreadSummary, ConversationUnreadThreads, ConversationReadInput, ConversationReadResult, SessionPreview, PreviewOpened, OpenPreviewInput, SessionForked, BackgroundWorkHeld, BackgroundWorkChildDecl, BackgroundWorkStatus, MachineUpsizeOutcome, SessionWaitKind, SessionWaitState, CreateSessionWaitInput, SessionWait, SessionWaitCheck, SessionWaitCheckResult, SessionWaitCheckReview, SessionWaitCreated, SessionWaitList, SessionFileChange, SessionChangeSet, SessionChangeStats, SessionDiffReviewBound, ReviewSuggestion, SessionFileHold, SessionFilePlane, ReviewSuggestionInput, ReviewNotesPublished, ReviewGitCredential, SessionReviewDocument, ReviewSuggestionDecision, ReviewSuggestionDecisions, SessionMergeReportDetail, SessionMergeReport, SessionMergeGated, SessionDiscardReport, SessionPreflightFileRow, SessionChangePreflight, SessionRebaseReport, ConversationPageContext, SendConversationMessageInput, ConversationTurnState, SendConversationMessageResult, UnnotifiedMention, ConversationPresenceSnapshot, AgentListRow, StreamConversationOptions, ChannelSessionStatus, ChannelSessionRow, ChannelWorkerFacts, ChannelSessionsResponse, SessionDirectMessageSent, BranchClaimInfo, BranchClaimGranted, BranchClaimsReleased, BranchClaimState, SessionPerfBucket, SessionPerfHistoryPage, } from "./types/api-conversations.js";
12
12
  export type { ConversationMemberRole, ConversationMember, DocumentCapability, TemplateCapability, ScopeGrant, ArtifactScope, RunContext, SetScopeGrantsInput, SetTemplateScopeInput, } from "./types/api-scopes.js";
13
- export type { Project, ProjectUpdate, ProjectsPage, ProjectRole, ProjectMember, ProjectObject, ProjectObjectsPage, ProjectObjectCounts, ProjectSkippedFile, ProjectPreviewFile, ProjectAddPreview, AddProjectObjectInput, AddProjectObjectResult, RefreshProjectObjectResult, ProjectStatus, ProjectStatusThread, ProjectStatusTask, ProjectStatusPerson, ProjectStatusWorker, ProjectStatusActivity, ProjectStatusActivityKind, ProjectStatusWaitingOn, ProjectStatusWaitingCount, ProjectStatusCounts, ThreadStatus, ThreadStatusWorker, ThreadStatusWorkerState, ThreadStatusWorkerEffort, ThreadStatusTodo, ThreadStatusDirector, ThreadStatusOutput, ThreadStatusEvent, ChatWork, ChatWorkThread, ThreadStatusWaitingOn, ThreadStatusAssignee, ThreadStatusTodoActivity, ChatTodoPatch, ChatTodoComment, MeStatus, MeStatusCounts, } from "./types/api-projects.js";
13
+ export type { Project, ProjectUpdate, ProjectsPage, ProjectRole, ProjectMember, ProjectObject, ProjectObjectsPage, ProjectObjectCounts, ProjectSkippedFile, ProjectPreviewFile, ProjectAddPreview, AddProjectObjectInput, AddProjectObjectResult, RefreshProjectObjectResult, ProjectStatus, ProjectStatusThread, ProjectStatusTask, ProjectStatusPerson, ProjectStatusWorker, ProjectStatusActivity, ProjectStatusActivityKind, ProjectStatusWaitingOn, ProjectStatusWaitingCount, ProjectStatusCounts, ThreadStatus, ThreadStatusWorker, ThreadStatusWorkerState, ThreadStatusWorkerEffort, WorkerFunding, ThreadStatusTodo, ThreadStatusDirector, ThreadStatusOutput, ThreadStatusEvent, ChatWork, ChatWorkThread, ThreadStatusWaitingOn, ThreadStatusAssignee, ThreadStatusTodoActivity, ChatTodoPatch, ChatTodoComment, MeStatus, MeStatusCounts, } from "./types/api-projects.js";
14
14
  export type { RegisterResult, RegisteredRuntime, RuntimeSourceInput, TemplateSourceRef, RegisterWorkflowInput, TemplateRow, TemplateDetail, ListTemplatesOptions, FactoryFileSearchRow, FactoryFolderSearchRow, SearchFactoryFilesOptions, FactoryFileSearchResult, FactoryFileWriteResult, FactoryFileListRow, ListFactoryFilesOptions, FactoryFileListPage, FactoryFileConflict, FactoryFileConflictList, ProjectSecretMeta, ProjectSecretList, PublicFileLinkState, FactoryRow, CreateFactoryInput, UpdateFactoryInput, FactoryPerfSummary, ScheduleRow, CreateScheduleInput, SecretOptions, SetSecretResult, SecretListEntry, SessionSecretEntry, SessionSecretInput, SessionSecretRequestCreated, SessionSecretRequestStatus, SessionSecretRequestSummary, VaultRequestKind, VaultKeyShape, VaultCatalogEntry, RequestedVaultEntry, VaultCardHint, CreateApiKeyInput, ApiKey, ApiKeyCreated, ListApiKeysOptions, ApiKeyPage, UsageRollupRow, UsageResponse, DriveRepoLink, CreateDriveRepoLinkInput, CreateNativeRepoInput, CreateNativeRepoResult, DriveMountSession, CreateDriveMountSessionInput, ConnectorGrantSummary, } from "./types/api-factory.js";
15
15
  export type { ComplianceScopeKind, ComplianceStatus, ComplianceSession, ComplianceAccess, RequestComplianceSessionInput, ListComplianceSessionsOptions, ComplianceSessionsPage, ListComplianceAccessesOptions, ComplianceAccessesPage, } from "./types/api-compliance.js";
16
16
  export interface AgentComposeClientOptions {
@@ -173,6 +173,18 @@ export declare class AgentComposeClient {
173
173
  * name (substring) — `listRuns({ workflow: "report", limit: 1 })` is
174
174
  * "the latest report run". */
175
175
  listRuns(opts?: ListRunsOptions): Promise<RunListEntry[]>;
176
+ /** A space's workflow activity: one stack per workflow of the space's own
177
+ * that has run there in the last 90 days — or, with `q`, that has a run
178
+ * matching the search, however old — the most recently run first, each
179
+ * with its latest (matching) run and what started it. The platform's
180
+ * default workflows (dynamic-task, repo-ingest, …) are left out, the
181
+ * search included. Paged by `cursor`. */
182
+ listWorkflowActivity(opts?: ListWorkflowActivityOptions): Promise<WorkflowActivityPage>;
183
+ /** One workflow's runs in a space, newest first, by its exact registered
184
+ * name (`listRuns`' `workflow` is a substring match): the last 90 days,
185
+ * or with `q` every run matching the search; a platform default's name
186
+ * answers with no runs. Paged by `cursor`. */
187
+ listWorkflowRuns(opts: ListWorkflowRunsOptions): Promise<WorkflowRunsPage>;
176
188
  /** Ordered lifecycle timeline for one run. */
177
189
  getRunTimeline(runId: string, opts?: {
178
190
  limit?: number;
package/dist/index.d.ts CHANGED
@@ -24,10 +24,10 @@ export { RequestContext, ReservedKeyError, NonSerialisableValueError, AC_RESERVE
24
24
  export type { RequestContextReserved, RequestContextWire, } from "./request-context/index.js";
25
25
  export { Verdict, runProcessorChain, denyTools, humanApproval, requireScope, redactPattern, createGatePauseProcessor, createAskHumanProcessor, ASK_USER_QUESTION_TOOL, } from "./processors/index.js";
26
26
  export type { Processor, ProcessorContext, ProcessorVerdict, ToolCall, GatePausePolicy, GatePauseApproval, GatePauseConnection, } from "./processors/index.js";
27
- export type { AgentMessage, AgentMessageInit, AgentMessageText, AgentMessageThinking, AgentMessageToolUse, AgentMessageToolResult, AgentMessageDone, AgentMessageError, AgentMessageUsage, AgentMessageModelUsage, AgentMessagePlanLimits, AgentMessageTaskNotification, AgentMessageTaskProgress, WorkflowProgressEntry, AgentMessageHarnessNotice, AgentMessageCompaction, AgentMessageSubagentUserMessage, AgentStatus, } from "./types/protocol.js";
27
+ export type { AgentMessage, AgentMessageInit, AgentMessageText, AgentMessageThinking, AgentMessageToolUse, AgentMessageToolResult, AgentMessageDone, AgentMessageError, AgentMessageUsage, AgentMessageModelUsage, AgentMessagePlanLimits, AgentMessageTaskNotification, AgentMessageTaskProgress, WorkflowProgressEntry, AgentMessageHarnessNotice, AgentMessageCompaction, AgentMessageSubagentUserMessage, AgentMessageModelReport, AgentStatus, } from "./types/protocol.js";
28
28
  export type { SandboxProvider, DesktopSandboxProvider, SandboxPtyOpts, SandboxPtyHandle, } from "./types/sandbox.js";
29
29
  export { AgentComposeClient } from "./client.js";
30
- export type { RegisterResult, RegisterWorkflowInput, RuntimeSourceInput, TemplateSourceRef, InvokeWorkflowOptions, InvokeAndWaitOptions, InvokeResult, FundingChoice, InlineWorkflowPayload, InvokeInlineOptions, InvokeInlineAndWaitOptions, ListSnapshotsOptions, TemplateRow, ListTemplatesOptions, CreateFactoryInput, UpdateFactoryInput, SecretOptions, SetSecretResult, SecretListEntry, SessionSecretEntry, SessionSecretInput, SessionSecretRequestCreated, SessionSecretRequestStatus, SessionSecretRequestSummary, VaultRequestKind, VaultKeyShape, VaultCatalogEntry, CreateApiKeyInput, StreamRunLogsOptions, TeamMember, Mention, CreateMentionsInput, EventSubjectType, EventRow, ReportEventInput, ListEventsOptions, ListEventsResult, RunLogLine, ListRunLogsOptions, RunListEntry, ListRunsOptions, RunDetail, FundingLane, RunFundingStamp, RunFundingUsageRow, RunFundingResponse, RunStepUsage, RunStepUsageResponse, RegisteredRuntime, RunState, RunStatus, FactoryRow, SnapshotListEntry, SnapshotListResponse, ApiKey, ApiKeyCreated, ListApiKeysOptions, ApiKeyPage, UsageRollupRow, UsageResponse, CancelRunResponse, RequestAgentPauseOptions, RequestAgentPauseResponse, SendAgentMessageOptions, SendAgentMessageResponse, AnswerSteerOptions, ResumePauseOptions, ResumePauseResponse, ResumePauseSuccess, ResumePausePending, ResumePauseActor, ConversationMessagePart, ConversationRow, ConversationProject, ConversationMessageRow, CreateChatInput, ChannelIvyState, IvyConnection, HiddenIvyConnection, IvyConnectionsView, IvyConnectionScope, ListingPage, DriveShareItem, DriveShare, HiddenDriveShare, DriveSharesView, WorkspaceConnection, WorkspaceConnectionAudienceEntry, WorkspaceConnectionsScopeView, ConversationsPage, ConversationDetail, ConversationThread, ConversationUnreadSummary, ConversationUnreadThreads, ConversationReadInput, ConversationReadResult, ConversationPageContext, SendConversationMessageInput, SendConversationMessageResult, UnnotifiedMention, ConversationTurnState, ConversationPresenceSnapshot, StreamConversationOptions, AgentListRow, CreateCloudSessionInput, CloudSessionCreated, SessionPreview, PreviewOpened, OpenPreviewInput, SessionForked, BackgroundWorkHeld, BackgroundWorkChildDecl, BackgroundWorkStatus, SessionWaitKind, SessionWaitState, CreateSessionWaitInput, SessionWait, SessionWaitCheck, SessionWaitCheckResult, SessionWaitCheckReview, SessionWaitCreated, SessionWaitList, SessionFileChange, SessionChangeSet, SessionChangeStats, SessionDiffReviewBound, ReviewSuggestion, SessionFileHold, SessionFilePlane, ReviewSuggestionInput, ReviewNotesPublished, ReviewGitCredential, SessionReviewDocument, ReviewSuggestionDecision, ReviewSuggestionDecisions, SessionMergeReportDetail, SessionMergeReport, SessionMergeGated, SessionDiscardReport, SessionPreflightFileRow, SessionChangePreflight, SessionRebaseReport, DriveMountSession, CreateDriveMountSessionInput, ChannelSessionStatus, ChannelSessionRow, ChannelWorkerFacts, ChannelSessionsResponse, SessionDirectMessageSent, BranchClaimInfo, BranchClaimGranted, BranchClaimsReleased, BranchClaimState, SessionPerfBucket, SessionPerfHistoryPage, FactoryPerfSummary, FactoryFileSearchRow, FactoryFolderSearchRow, SearchFactoryFilesOptions, FactoryFileSearchResult, PublicFileLinkState, FactoryFileListRow, ListFactoryFilesOptions, FactoryFileListPage, FactoryFileConflict, FactoryFileConflictList, ProjectSecretMeta, ProjectSecretList, ConversationMemberRole, ConversationMember, DocumentCapability, TemplateCapability, ScopeGrant, ArtifactScope, RunContext, SetScopeGrantsInput, SetTemplateScopeInput, TemplateDetail, Project, ProjectUpdate, ProjectsPage, ProjectRole, ProjectMember, ProjectObject, ProjectObjectsPage, ProjectObjectCounts, ProjectSkippedFile, ProjectPreviewFile, ProjectAddPreview, AddProjectObjectInput, AddProjectObjectResult, RefreshProjectObjectResult, ProjectStatus, ProjectStatusThread, ProjectStatusTask, ProjectStatusPerson, ProjectStatusWorker, ProjectStatusActivity, ProjectStatusActivityKind, ProjectStatusWaitingOn, ProjectStatusWaitingCount, ProjectStatusCounts, ThreadStatus, ThreadStatusWorker, ThreadStatusWorkerState, ThreadStatusWorkerEffort, ThreadStatusTodo, ThreadStatusDirector, ThreadStatusOutput, ThreadStatusEvent, ThreadStatusWaitingOn, ThreadStatusAssignee, ThreadStatusTodoActivity, ChatTodoPatch, ChatTodoComment, ChatWork, ChatWorkThread, MeStatus, MeStatusCounts, ComplianceScopeKind, ComplianceStatus, ComplianceSession, ComplianceAccess, RequestComplianceSessionInput, ListComplianceSessionsOptions, ComplianceSessionsPage, ListComplianceAccessesOptions, ComplianceAccessesPage, } from "./client.js";
30
+ export type { RegisterResult, RegisterWorkflowInput, RuntimeSourceInput, TemplateSourceRef, InvokeWorkflowOptions, InvokeAndWaitOptions, InvokeResult, FundingChoice, InlineWorkflowPayload, InvokeInlineOptions, InvokeInlineAndWaitOptions, ListSnapshotsOptions, TemplateRow, ListTemplatesOptions, CreateFactoryInput, UpdateFactoryInput, SecretOptions, SetSecretResult, SecretListEntry, SessionSecretEntry, SessionSecretInput, SessionSecretRequestCreated, SessionSecretRequestStatus, SessionSecretRequestSummary, VaultRequestKind, VaultKeyShape, VaultCatalogEntry, CreateApiKeyInput, StreamRunLogsOptions, TeamMember, Mention, CreateMentionsInput, EventSubjectType, EventRow, ReportEventInput, ListEventsOptions, ListEventsResult, RunLogLine, ListRunLogsOptions, RunListEntry, ListRunsOptions, RunDetail, RunStartedBy, WorkflowActivityRun, WorkflowActivityHead, ListWorkflowActivityOptions, ListWorkflowRunsOptions, WorkflowActivityPage, WorkflowRunsPage, FundingLane, RunFundingStamp, RunFundingUsageRow, RunFundingResponse, RunStepUsage, RunStepUsageResponse, RegisteredRuntime, RunState, RunStatus, FactoryRow, SnapshotListEntry, SnapshotListResponse, ApiKey, ApiKeyCreated, ListApiKeysOptions, ApiKeyPage, UsageRollupRow, UsageResponse, CancelRunResponse, RequestAgentPauseOptions, RequestAgentPauseResponse, SendAgentMessageOptions, SendAgentMessageResponse, AnswerSteerOptions, ResumePauseOptions, ResumePauseResponse, ResumePauseSuccess, ResumePausePending, ResumePauseActor, ConversationMessagePart, ConversationRow, ConversationProject, ConversationMessageRow, CreateChatInput, ChannelIvyState, IvyConnection, HiddenIvyConnection, IvyConnectionsView, IvyConnectionScope, ListingPage, DriveShareItem, DriveShare, HiddenDriveShare, DriveSharesView, WorkspaceConnection, WorkspaceConnectionAudienceEntry, WorkspaceConnectionsScopeView, ConversationsPage, ConversationDetail, ConversationThread, ConversationUnreadSummary, ConversationUnreadThreads, ConversationReadInput, ConversationReadResult, ConversationPageContext, SendConversationMessageInput, SendConversationMessageResult, UnnotifiedMention, ConversationTurnState, ConversationPresenceSnapshot, StreamConversationOptions, AgentListRow, CreateCloudSessionInput, CloudSessionCreated, SessionPreview, PreviewOpened, OpenPreviewInput, SessionForked, BackgroundWorkHeld, BackgroundWorkChildDecl, BackgroundWorkStatus, SessionWaitKind, SessionWaitState, CreateSessionWaitInput, SessionWait, SessionWaitCheck, SessionWaitCheckResult, SessionWaitCheckReview, SessionWaitCreated, SessionWaitList, SessionFileChange, SessionChangeSet, SessionChangeStats, SessionDiffReviewBound, ReviewSuggestion, SessionFileHold, SessionFilePlane, ReviewSuggestionInput, ReviewNotesPublished, ReviewGitCredential, SessionReviewDocument, ReviewSuggestionDecision, ReviewSuggestionDecisions, SessionMergeReportDetail, SessionMergeReport, SessionMergeGated, SessionDiscardReport, SessionPreflightFileRow, SessionChangePreflight, SessionRebaseReport, DriveMountSession, CreateDriveMountSessionInput, ChannelSessionStatus, ChannelSessionRow, ChannelWorkerFacts, ChannelSessionsResponse, SessionDirectMessageSent, BranchClaimInfo, BranchClaimGranted, BranchClaimsReleased, BranchClaimState, SessionPerfBucket, SessionPerfHistoryPage, FactoryPerfSummary, FactoryFileSearchRow, FactoryFolderSearchRow, SearchFactoryFilesOptions, FactoryFileSearchResult, PublicFileLinkState, FactoryFileListRow, ListFactoryFilesOptions, FactoryFileListPage, FactoryFileConflict, FactoryFileConflictList, ProjectSecretMeta, ProjectSecretList, ConversationMemberRole, ConversationMember, DocumentCapability, TemplateCapability, ScopeGrant, ArtifactScope, RunContext, SetScopeGrantsInput, SetTemplateScopeInput, TemplateDetail, Project, ProjectUpdate, ProjectsPage, ProjectRole, ProjectMember, ProjectObject, ProjectObjectsPage, ProjectObjectCounts, ProjectSkippedFile, ProjectPreviewFile, ProjectAddPreview, AddProjectObjectInput, AddProjectObjectResult, RefreshProjectObjectResult, ProjectStatus, ProjectStatusThread, ProjectStatusTask, ProjectStatusPerson, ProjectStatusWorker, ProjectStatusActivity, ProjectStatusActivityKind, ProjectStatusWaitingOn, ProjectStatusWaitingCount, ProjectStatusCounts, ThreadStatus, ThreadStatusWorker, ThreadStatusWorkerState, ThreadStatusWorkerEffort, WorkerFunding, ThreadStatusTodo, ThreadStatusDirector, ThreadStatusOutput, ThreadStatusEvent, ThreadStatusWaitingOn, ThreadStatusAssignee, ThreadStatusTodoActivity, ChatTodoPatch, ChatTodoComment, ChatWork, ChatWorkThread, MeStatus, MeStatusCounts, ComplianceScopeKind, ComplianceStatus, ComplianceSession, ComplianceAccess, RequestComplianceSessionInput, ListComplianceSessionsOptions, ComplianceSessionsPage, ListComplianceAccessesOptions, ComplianceAccessesPage, } from "./client.js";
31
31
  export { parseSseStream } from "./sse.js";
32
32
  export { renderDirectiveMarker, parseDirectiveMarkers, DIRECTIVE_MARKER_PREFIX, DIRECTIVE_MARKER_SUFFIX, MAX_DIRECTIVES_PER_OUTPUT, REVISION_SELECTOR_RE, ASK_DIRECTIVE_PROMPT_MAX, ASK_DIRECTIVE_MAX_OPTIONS, ASK_DIRECTIVE_OPTION_ID_MAX, ASK_DIRECTIVE_OPTION_LABEL_MAX, ASK_APPROVER_MIN, ASK_APPROVER_MAX, TAKEOVER_NOTE_MAX_CHARS, } from "./directives.js";
33
33
  export type { CloudDirective } from "./directives.js";
package/dist/index.js CHANGED
@@ -1604,6 +1604,30 @@ class AgentComposeClient {
1604
1604
  const body = await this.fetch(`/api/v1/factories/${slug}/runs${q2.toString() ? `?${q2}` : ""}`);
1605
1605
  return body.workflows;
1606
1606
  }
1607
+ async listWorkflowActivity(opts = {}) {
1608
+ const q2 = new URLSearchParams;
1609
+ if (opts.limit !== undefined)
1610
+ q2.set("limit", String(opts.limit));
1611
+ if (opts.cursor)
1612
+ q2.set("cursor", opts.cursor);
1613
+ if (opts.q)
1614
+ q2.set("q", opts.q);
1615
+ const slug = encodeURIComponent(opts.factorySlug ?? "default");
1616
+ const body = await this.fetch(`/api/v1/factories/${slug}/workflow-activity${q2.toString() ? `?${q2}` : ""}`);
1617
+ return { workflows: body.workflows, hasMore: body.has_more, nextCursor: body.next_cursor };
1618
+ }
1619
+ async listWorkflowRuns(opts) {
1620
+ const q2 = new URLSearchParams({ workflow: opts.workflow });
1621
+ if (opts.limit !== undefined)
1622
+ q2.set("limit", String(opts.limit));
1623
+ if (opts.cursor)
1624
+ q2.set("cursor", opts.cursor);
1625
+ if (opts.q)
1626
+ q2.set("q", opts.q);
1627
+ const slug = encodeURIComponent(opts.factorySlug ?? "default");
1628
+ const body = await this.fetch(`/api/v1/factories/${slug}/workflow-activity/runs?${q2}`);
1629
+ return { runs: body.runs, hasMore: body.has_more, nextCursor: body.next_cursor };
1630
+ }
1607
1631
  async getRunTimeline(runId, opts) {
1608
1632
  const q2 = new URLSearchParams;
1609
1633
  if (opts?.limit !== undefined)
@@ -3594,7 +3618,7 @@ Re-emit the COMPLETE corrected <response> JSON now: every required field present
3594
3618
  continue;
3595
3619
  }
3596
3620
  const msg = outputVerdict.value;
3597
- if (msg.type === "text_delta" || msg.type === "usage_delta" || msg.type === "plan_limits" || msg.type === "task_notification" || msg.type === "task_progress" || msg.type === "harness_notice" || msg.type === "compaction" || msg.type === "subagent_user_message")
3621
+ if (msg.type === "text_delta" || msg.type === "usage_delta" || msg.type === "plan_limits" || msg.type === "task_notification" || msg.type === "task_progress" || msg.type === "harness_notice" || msg.type === "compaction" || msg.type === "subagent_user_message" || msg.type === "model_report")
3598
3622
  continue;
3599
3623
  opts.onAgentEvent?.(iteration, msg);
3600
3624
  const summary = summarizeAgentMessage(msg);
@@ -3741,6 +3765,17 @@ function parseRawJsonResponse(text) {
3741
3765
  }
3742
3766
  }
3743
3767
 
3768
+ // src/runtimes/_reported-model.ts
3769
+ var MODEL_ID_MAX = 200;
3770
+ function reportedModelId(raw) {
3771
+ if (typeof raw !== "string")
3772
+ return;
3773
+ const id = raw.replace(/\[[^\]]*\]$/, "").trim();
3774
+ if (id.length === 0 || id === "<synthetic>")
3775
+ return;
3776
+ return id.length > MODEL_ID_MAX ? id.slice(0, MODEL_ID_MAX) : id;
3777
+ }
3778
+
3744
3779
  // src/runtimes/claude.ts
3745
3780
  function now3() {
3746
3781
  return new Date().toISOString();
@@ -3750,10 +3785,16 @@ function translateMessage(message) {
3750
3785
  const msgs = [];
3751
3786
  if (message.type === "system" && message.subtype === "init") {
3752
3787
  msgs.push({ type: "init", sessionId: String(message.session_id ?? ""), timestamp: ts });
3788
+ const model = reportedModelId(message.model);
3789
+ if (model)
3790
+ msgs.push({ type: "model_report", model, timestamp: ts });
3753
3791
  return msgs;
3754
3792
  }
3755
3793
  if (message.type === "assistant") {
3756
3794
  const raw = message.message;
3795
+ const model = typeof message.parent_tool_use_id === "string" ? undefined : reportedModelId(raw?.model);
3796
+ if (model)
3797
+ msgs.push({ type: "model_report", model, timestamp: ts });
3757
3798
  for (const block of raw?.content ?? []) {
3758
3799
  const b = block;
3759
3800
  if (b.type === "text")
@@ -4284,6 +4325,13 @@ function streamInputFeederFragment(paths) {
4284
4325
  }
4285
4326
  function wrapMidTurnUserMessage(text, opts) {
4286
4327
  const relayedFrom = opts?.relayedFrom?.trim();
4328
+ if (opts?.platformNotice) {
4329
+ return `The platform posted a notice in this conversation while you were working:
4330
+
4331
+ ` + text + `
4332
+
4333
+ Act on it as you continue this turn.`;
4334
+ }
4287
4335
  const head = relayedFrom ? `A message relaying ${relayedFrom}'s own words arrived while you were working:
4288
4336
 
4289
4337
  ` : opts?.fromOwnerAgent ? `The agent that owns your thread sent a message while you were working:
@@ -5808,7 +5856,9 @@ var claudeCodeSpec = {
5808
5856
  const message = p.message;
5809
5857
  const synthetic = message?.model === "<synthetic>";
5810
5858
  const blocks2 = Array.isArray(message?.content) ? message.content : [];
5811
- return blocks2.flatMap((b) => {
5859
+ const model = parentId ? undefined : reportedModelId(message?.model);
5860
+ const report = model ? [{ type: "model_report", model, timestamp: ts }] : [];
5861
+ return report.concat(blocks2.flatMap((b) => {
5812
5862
  if (b.type === "text" && typeof b.text === "string" && b.text.length > 0) {
5813
5863
  return [{ type: synthetic ? "harness_notice" : "text", text: b.text, timestamp: ts }];
5814
5864
  }
@@ -5826,7 +5876,7 @@ var claudeCodeSpec = {
5826
5876
  }];
5827
5877
  }
5828
5878
  return [];
5829
- });
5879
+ }));
5830
5880
  }
5831
5881
  case "user": {
5832
5882
  const message = p.message;
@@ -5910,6 +5960,10 @@ var claudeCodeSpec = {
5910
5960
  return limits ? [limits] : [];
5911
5961
  }
5912
5962
  case "system": {
5963
+ if (p.subtype === "init") {
5964
+ const model = reportedModelId(p.model);
5965
+ return model ? [{ type: "model_report", model, timestamp: ts }] : [];
5966
+ }
5913
5967
  if (p.subtype === "task_progress") {
5914
5968
  const progress = parseSystemTaskProgress(p, ts);
5915
5969
  return progress ? [progress] : [];
@@ -243,10 +243,13 @@ export declare function wrapMidTurnUserMessage(text: string, opts?: MidTurnEnvel
243
243
  /** Who a mid-turn message speaks for, when it is not the session user.
244
244
  * `relayedFrom` = the display name of the person whose own words an agent
245
245
  * relayed verbatim; `fromOwnerAgent` = the thread agent that owns this
246
- * worker, in its own words; both absent = the session user's own message. */
246
+ * worker, in its own words; `platformNotice` = a system notice the
247
+ * platform posted to wake the conversation (nobody's words); all absent =
248
+ * the session user's own message. */
247
249
  export interface MidTurnEnvelopeOptions {
248
250
  relayedFrom?: string | null;
249
251
  fromOwnerAgent?: boolean;
252
+ platformNotice?: boolean;
250
253
  }
251
254
  /** The one delivery-ack exec `injectUserMessage` runs: append the message
252
255
  * line to the durable inbox, then wait for the feeder's delivered counter
@@ -0,0 +1,16 @@
1
+ /**
2
+ * A model id as a harness names it — the one derivation behind every
3
+ * `model_report` the Claude runtimes emit (AgentMessageModelReport): the
4
+ * `model` on claude-code's `system`/`init` event and the `message.model` on
5
+ * each `assistant` event, which the Agent SDK's messages mirror.
6
+ *
7
+ * - claude-code's `[1m]`-style suffix (`claude-opus-4-8[1m]`) is the CLI's
8
+ * context-window marker: a variant flag on the same model, not another
9
+ * model, so the report drops it;
10
+ * - `<synthetic>` is the harness's own voice (slash-command stdout,
11
+ * advisories) and names no model;
12
+ * - anything that is not a non-empty string names none.
13
+ *
14
+ * Machine-format rules only; nothing here reads words.
15
+ */
16
+ export declare function reportedModelId(raw: unknown): string | undefined;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The harness's own report of the model it runs (AgentMessageModelReport,
3
+ * owner 2026-10-06: "what model actually did the work"), one case per
4
+ * branch of the one derivation (_reported-model.ts) and of the specs that
5
+ * emit it:
6
+ * - claude-code's `system`/`init` names the session's model, minus the
7
+ * CLI's `[1m]` context-window marker; an init without one names none;
8
+ * - a top-level `assistant` event names the model the API answered with,
9
+ * before its content; the harness's own voice (`<synthetic>`) and a
10
+ * subagent's event (`parent_tool_use_id`) name none;
11
+ * - codex's and opencode's streams carry no model: their specs emit no
12
+ * report for the events that would carry one.
13
+ */
14
+ export {};
@@ -1604,6 +1604,30 @@ class AgentComposeClient {
1604
1604
  const body = await this.fetch(`/api/v1/factories/${slug}/runs${q2.toString() ? `?${q2}` : ""}`);
1605
1605
  return body.workflows;
1606
1606
  }
1607
+ async listWorkflowActivity(opts = {}) {
1608
+ const q2 = new URLSearchParams;
1609
+ if (opts.limit !== undefined)
1610
+ q2.set("limit", String(opts.limit));
1611
+ if (opts.cursor)
1612
+ q2.set("cursor", opts.cursor);
1613
+ if (opts.q)
1614
+ q2.set("q", opts.q);
1615
+ const slug = encodeURIComponent(opts.factorySlug ?? "default");
1616
+ const body = await this.fetch(`/api/v1/factories/${slug}/workflow-activity${q2.toString() ? `?${q2}` : ""}`);
1617
+ return { workflows: body.workflows, hasMore: body.has_more, nextCursor: body.next_cursor };
1618
+ }
1619
+ async listWorkflowRuns(opts) {
1620
+ const q2 = new URLSearchParams({ workflow: opts.workflow });
1621
+ if (opts.limit !== undefined)
1622
+ q2.set("limit", String(opts.limit));
1623
+ if (opts.cursor)
1624
+ q2.set("cursor", opts.cursor);
1625
+ if (opts.q)
1626
+ q2.set("q", opts.q);
1627
+ const slug = encodeURIComponent(opts.factorySlug ?? "default");
1628
+ const body = await this.fetch(`/api/v1/factories/${slug}/workflow-activity/runs?${q2}`);
1629
+ return { runs: body.runs, hasMore: body.has_more, nextCursor: body.next_cursor };
1630
+ }
1607
1631
  async getRunTimeline(runId, opts) {
1608
1632
  const q2 = new URLSearchParams;
1609
1633
  if (opts?.limit !== undefined)
@@ -3594,7 +3618,7 @@ Re-emit the COMPLETE corrected <response> JSON now: every required field present
3594
3618
  continue;
3595
3619
  }
3596
3620
  const msg = outputVerdict.value;
3597
- if (msg.type === "text_delta" || msg.type === "usage_delta" || msg.type === "plan_limits" || msg.type === "task_notification" || msg.type === "task_progress" || msg.type === "harness_notice" || msg.type === "compaction" || msg.type === "subagent_user_message")
3621
+ if (msg.type === "text_delta" || msg.type === "usage_delta" || msg.type === "plan_limits" || msg.type === "task_notification" || msg.type === "task_progress" || msg.type === "harness_notice" || msg.type === "compaction" || msg.type === "subagent_user_message" || msg.type === "model_report")
3598
3622
  continue;
3599
3623
  opts.onAgentEvent?.(iteration, msg);
3600
3624
  const summary = summarizeAgentMessage(msg);
@@ -3741,6 +3765,17 @@ function parseRawJsonResponse(text) {
3741
3765
  }
3742
3766
  }
3743
3767
 
3768
+ // src/runtimes/_reported-model.ts
3769
+ var MODEL_ID_MAX = 200;
3770
+ function reportedModelId(raw) {
3771
+ if (typeof raw !== "string")
3772
+ return;
3773
+ const id = raw.replace(/\[[^\]]*\]$/, "").trim();
3774
+ if (id.length === 0 || id === "<synthetic>")
3775
+ return;
3776
+ return id.length > MODEL_ID_MAX ? id.slice(0, MODEL_ID_MAX) : id;
3777
+ }
3778
+
3744
3779
  // src/runtimes/claude.ts
3745
3780
  function now3() {
3746
3781
  return new Date().toISOString();
@@ -3750,10 +3785,16 @@ function translateMessage(message) {
3750
3785
  const msgs = [];
3751
3786
  if (message.type === "system" && message.subtype === "init") {
3752
3787
  msgs.push({ type: "init", sessionId: String(message.session_id ?? ""), timestamp: ts });
3788
+ const model = reportedModelId(message.model);
3789
+ if (model)
3790
+ msgs.push({ type: "model_report", model, timestamp: ts });
3753
3791
  return msgs;
3754
3792
  }
3755
3793
  if (message.type === "assistant") {
3756
3794
  const raw = message.message;
3795
+ const model = typeof message.parent_tool_use_id === "string" ? undefined : reportedModelId(raw?.model);
3796
+ if (model)
3797
+ msgs.push({ type: "model_report", model, timestamp: ts });
3757
3798
  for (const block of raw?.content ?? []) {
3758
3799
  const b = block;
3759
3800
  if (b.type === "text")
@@ -4284,6 +4325,13 @@ function streamInputFeederFragment(paths) {
4284
4325
  }
4285
4326
  function wrapMidTurnUserMessage(text, opts) {
4286
4327
  const relayedFrom = opts?.relayedFrom?.trim();
4328
+ if (opts?.platformNotice) {
4329
+ return `The platform posted a notice in this conversation while you were working:
4330
+
4331
+ ` + text + `
4332
+
4333
+ Act on it as you continue this turn.`;
4334
+ }
4287
4335
  const head = relayedFrom ? `A message relaying ${relayedFrom}'s own words arrived while you were working:
4288
4336
 
4289
4337
  ` : opts?.fromOwnerAgent ? `The agent that owns your thread sent a message while you were working:
@@ -5808,7 +5856,9 @@ var claudeCodeSpec = {
5808
5856
  const message = p.message;
5809
5857
  const synthetic = message?.model === "<synthetic>";
5810
5858
  const blocks2 = Array.isArray(message?.content) ? message.content : [];
5811
- return blocks2.flatMap((b) => {
5859
+ const model = parentId ? undefined : reportedModelId(message?.model);
5860
+ const report = model ? [{ type: "model_report", model, timestamp: ts }] : [];
5861
+ return report.concat(blocks2.flatMap((b) => {
5812
5862
  if (b.type === "text" && typeof b.text === "string" && b.text.length > 0) {
5813
5863
  return [{ type: synthetic ? "harness_notice" : "text", text: b.text, timestamp: ts }];
5814
5864
  }
@@ -5826,7 +5876,7 @@ var claudeCodeSpec = {
5826
5876
  }];
5827
5877
  }
5828
5878
  return [];
5829
- });
5879
+ }));
5830
5880
  }
5831
5881
  case "user": {
5832
5882
  const message = p.message;
@@ -5910,6 +5960,10 @@ var claudeCodeSpec = {
5910
5960
  return limits ? [limits] : [];
5911
5961
  }
5912
5962
  case "system": {
5963
+ if (p.subtype === "init") {
5964
+ const model = reportedModelId(p.model);
5965
+ return model ? [{ type: "model_report", model, timestamp: ts }] : [];
5966
+ }
5913
5967
  if (p.subtype === "task_progress") {
5914
5968
  const progress = parseSystemTaskProgress(p, ts);
5915
5969
  return progress ? [progress] : [];
@@ -96,6 +96,18 @@ export interface RegisterWorkflowInput {
96
96
  factoryDrive?: "required" | "none";
97
97
  /** Factory slug. Defaults to `"default"`. */
98
98
  factorySlug?: string;
99
+ /** Register INTO a project (`agentc register --project`, ADR-0087): the
100
+ * workflow, its schedules and its runs are visible to the project's
101
+ * members alone, read live, so leaving the project loses them — the
102
+ * registrant included (the workflow belongs to the project, with no
103
+ * personal owner). Any member with a write or owner seat in the project
104
+ * may register into it on a key that holds `invoke`; the `manage` scope
105
+ * is not needed. A read seat is refused (403 `role_read_only`); a
106
+ * project the registrant cannot see answers 404 exactly as one that does
107
+ * not exist. Omitted, a registration from a terminal or an API key is
108
+ * the whole space's and takes `manage` (403 `manage_required`
109
+ * otherwise). */
110
+ projectId?: string;
99
111
  }
100
112
  export interface TemplateRow {
101
113
  name: string;
@@ -305,6 +317,8 @@ export interface UpdateFactoryInput {
305
317
  }
306
318
  export interface ScheduleRow {
307
319
  id: string;
320
+ /** The factory the schedule (and the workflow it fires) lives in. */
321
+ factoryId: string;
308
322
  name: string;
309
323
  workflowName: string;
310
324
  cron: string;
@@ -371,9 +385,14 @@ export interface SessionSecretRequestCreated {
371
385
  * open ask's link already went out and nothing new exists to send. */
372
386
  url: string | null;
373
387
  expiresAt: string;
374
- /** True = a standing auto-approve set already filled the request at the
375
- * mint — nothing is pending; source the session env now. */
388
+ /** True = a standing auto-approve set or this work's grant already filled
389
+ * the request at the mint — nothing is pending. */
376
390
  autoApproved?: boolean;
391
+ /** With autoApproved: true = the values are on the session's RUNNING
392
+ * machine now (its env file, and its egress ruleset for a brokered key),
393
+ * so re-sourcing the session env loads them; false = no machine is
394
+ * running or the push failed, and they land when the next turn starts. */
395
+ loaded?: boolean;
377
396
  /** Set with autoApproved when the grant came from this work's earlier
378
397
  * worker (the same person's grant, carried with no card): who gave it. */
379
398
  carried?: {
@@ -178,10 +178,20 @@ export interface ProjectStatusWaitingOn {
178
178
  who: string;
179
179
  /** What they will do or answer, in the people's terms. */
180
180
  what: string | null;
181
- kind: "task" | "question";
181
+ /** `task`: a plan task waiting on a person; `question`: a worker's
182
+ * question owed an answer; `answer`: the thread's own question to a
183
+ * person (its raise declared whom it waits on), open until one of them
184
+ * answers where Ivy spoke. */
185
+ kind: "task" | "question" | "answer";
182
186
  /** The chat message where the person said it, when the thread agent
183
- * recorded one: the way to the ask. Null otherwise. */
187
+ * recorded one, or Ivy's message carrying the thread's question: the way
188
+ * to the ask. Null otherwise. */
184
189
  messageId: string | null;
190
+ /** An answer wait's place: the chat thread Ivy spoke in (null for the
191
+ * room's top level). Absent on the other kinds. */
192
+ threadRootId?: string | null;
193
+ /** When the thread asked (ISO). Absent on the other kinds. */
194
+ at?: string | null;
185
195
  }
186
196
  /** Whom a TASK waits on (owner 2026-10-05: a todo may wait on more than one
187
197
  * person's answer or sign-off): every teammate it names, as people, and
@@ -359,6 +369,22 @@ export interface ProjectStatus {
359
369
  export type ThreadStatusWorkerState = "starting" | "working" | "done" | "failed" | "stopped";
360
370
  /** The effort a worker was started with; null = the harness's own default. */
361
371
  export type ThreadStatusWorkerEffort = "low" | "medium" | "high" | "xhigh" | "max";
372
+ /** What pays for a worker's inference, as its hover card says it (owner
373
+ * 2026-10-05: a findable detail, never a mark on rows): a person's connected
374
+ * plan (the person by id and name only, when the turn named them), platform
375
+ * credits, or a connected provider key by its provider family. */
376
+ export type WorkerFunding = {
377
+ lane: "subscription";
378
+ owner: {
379
+ id: string;
380
+ name: string | null;
381
+ } | null;
382
+ } | {
383
+ lane: "platform";
384
+ } | {
385
+ lane: "byok";
386
+ provider: string;
387
+ };
362
388
  export interface ThreadStatusWorker {
363
389
  /** The worker's session (its page is /conversations/:id). */
364
390
  conversationId: string;
@@ -376,8 +402,17 @@ export interface ThreadStatusWorker {
376
402
  result: string | null;
377
403
  /** The question it is parked on, while one is owed. */
378
404
  asking: string | null;
379
- /** The model stamped at birth; null = the runtime's own default. */
405
+ /** The model stamped at birth (what it was CONFIGURED to run); null =
406
+ * the runtime's own default. */
380
407
  model: string | null;
408
+ /** The models its turns ACTUALLY ran (owner 2026-10-06: "what model
409
+ * actually did the work"), each once in first-seen order — a mid-turn
410
+ * switch lists both: the harness's own report (its stream; codex's
411
+ * rollout file read at the turn's end), then the metering gateway's
412
+ * attested record of the model each platform-funded call went to. Never
413
+ * derived from `model`: empty when nothing is on record, and the
414
+ * surfaces then say the model isn't known. Absent on older servers. */
415
+ ranModels?: string[];
381
416
  effort: ThreadStatusWorkerEffort | null;
382
417
  /** The harness it runs ("claude-code", "codex", ...); null when unknown. */
383
418
  runtime: string | null;
@@ -386,11 +421,17 @@ export interface ThreadStatusWorker {
386
421
  executor: "local" | "cloud" | null;
387
422
  /** When its running turn started (ISO); null while no turn runs. */
388
423
  workingSince: string | null;
424
+ /** When its newest turn ended (ISO): the moment it stopped, while no turn
425
+ * runs. Null while a turn runs, and for a worker that has not run one. */
426
+ lastTurnEndedAt: string | null;
389
427
  /** Its machine has a live desktop to show (the Desktop pill's own
390
428
  * verdict, for the session's current machine): the chat draws a door to
391
429
  * it on the step the worker is on. False for a local session, a machine
392
430
  * with no GUI, or a session no longer on a machine. */
393
431
  desktopCapable: boolean;
432
+ /** What pays for it, when the record says (see WorkerFunding); null when
433
+ * nothing is on record. Absent on older servers. */
434
+ funding?: WorkerFunding | null;
394
435
  }
395
436
  /** A message that directed a step: who wrote it and the opening of what
396
437
  * they said, where it sits (its chat and, for a reply, the root of its
@@ -319,6 +319,81 @@ export interface ListRunsOptions {
319
319
  sort?: "newest" | "oldest" | "fastest" | "slowest";
320
320
  limit?: number;
321
321
  }
322
+ /** What started a run (`GET /factories/:slug/workflow-activity*`), read off
323
+ * the dispatch stamps: a schedule's tick, a thread's scripted check, the
324
+ * chat an agent's turn dispatched it from, the person who invoked it from
325
+ * the dashboard, or the API key (the CLI, a script). */
326
+ export type RunStartedBy = {
327
+ kind: "schedule";
328
+ name: string | null;
329
+ } | {
330
+ kind: "check";
331
+ } | {
332
+ kind: "chat";
333
+ conversationId: string;
334
+ title: string | null;
335
+ } | {
336
+ kind: "person";
337
+ userId: string;
338
+ name: string;
339
+ image: string | null;
340
+ avatarUrl: string | null;
341
+ } | {
342
+ kind: "key";
343
+ name: string;
344
+ } | {
345
+ kind: "unknown";
346
+ };
347
+ /** One run in a space's workflow activity: the runs list's summary plus
348
+ * what started it. */
349
+ export interface WorkflowActivityRun extends RunListEntry {
350
+ finalSummary: string | null;
351
+ /** Structured return value from the workflow, when it completed. */
352
+ output: unknown;
353
+ startedBy: RunStartedBy;
354
+ }
355
+ /** One stack in a space's workflow activity: a workflow that has run there
356
+ * and its latest run. */
357
+ export interface WorkflowActivityHead {
358
+ workflow: string;
359
+ latestRun: WorkflowActivityRun;
360
+ }
361
+ export interface ListWorkflowActivityOptions {
362
+ /** Factory the runs live in. Defaults to "default". */
363
+ factorySlug?: string;
364
+ /** Stacks per page (1–50, server default 20). */
365
+ limit?: number;
366
+ /** The previous page's `nextCursor`. */
367
+ cursor?: string;
368
+ /** A search (at most 100 characters): every run whose workflow name,
369
+ * title, failure or summary contains it, without case — reaching past
370
+ * the last 90 days the listing shows without one. */
371
+ q?: string;
372
+ }
373
+ export interface ListWorkflowRunsOptions {
374
+ /** Factory the runs live in. Defaults to "default". */
375
+ factorySlug?: string;
376
+ /** The registered workflow name, exactly. */
377
+ workflow: string;
378
+ /** Runs per page (1–50, server default 10). */
379
+ limit?: number;
380
+ /** The previous page's `nextCursor`. */
381
+ cursor?: string;
382
+ /** A search (at most 100 characters): the workflow's runs whose title,
383
+ * failure or summary contains it, without case — reaching past the last
384
+ * 90 days the listing shows without one. */
385
+ q?: string;
386
+ }
387
+ export interface WorkflowActivityPage {
388
+ workflows: WorkflowActivityHead[];
389
+ hasMore: boolean;
390
+ nextCursor: string | null;
391
+ }
392
+ export interface WorkflowRunsPage {
393
+ runs: WorkflowActivityRun[];
394
+ hasMore: boolean;
395
+ nextCursor: string | null;
396
+ }
322
397
  export interface TimelineEvent {
323
398
  kind: string;
324
399
  at: string;
@@ -336,7 +336,28 @@ export interface AgentMessageSubagentUserMessage extends AgentMessageBase {
336
336
  text: string;
337
337
  parentToolUseId: string;
338
338
  }
339
- export type AgentMessage = AgentMessageInit | AgentMessageText | AgentMessageTextDelta | AgentMessageThinking | AgentMessageToolUse | AgentMessageToolResult | AgentMessageDone | AgentMessageError | AgentMessageUsage | AgentMessageUsageDelta | AgentMessagePlanLimits | AgentMessagePlan | AgentMessageTaskNotification | AgentMessageTaskProgress | AgentMessageHarnessNotice | AgentMessageCompaction | AgentMessageSubagentUserMessage;
339
+ /** The harness's OWN report of the model it is running — never the
340
+ * platform's configuration (owner 2026-10-06: "It's very difficult to
341
+ * tell which model did this work"). claude-code names it twice: once on
342
+ * `system`/`init` (`model`, the session's resolved model) and on every
343
+ * top-level `assistant` event (`message.model`, the id the API answered
344
+ * with — the truth after a `/model` switch or a fallback; `<synthetic>`
345
+ * is the harness's own voice and names none; a subagent's events name the
346
+ * subagent's model, not the worker's, and are left out). The normaliser
347
+ * emits one report per naming, so a consumer that stamps the turn's
348
+ * models dedupes in order of first appearance and keeps every distinct
349
+ * id (a mid-turn switch records both). codex's `exec --json` events and
350
+ * opencode's `run --format json` lines carry no model at all (verified
351
+ * against both sources, 2026-10-06): those harnesses emit none, and the
352
+ * record stays honestly empty. Additive kind: existing producers never
353
+ * emit it. */
354
+ export interface AgentMessageModelReport extends AgentMessageBase {
355
+ type: "model_report";
356
+ /** The model id as the harness reports it, minus claude-code's
357
+ * `[1m]`-style context-window marker (runtimes/_reported-model.ts). */
358
+ model: string;
359
+ }
360
+ export type AgentMessage = AgentMessageInit | AgentMessageText | AgentMessageTextDelta | AgentMessageThinking | AgentMessageToolUse | AgentMessageToolResult | AgentMessageDone | AgentMessageError | AgentMessageUsage | AgentMessageUsageDelta | AgentMessagePlanLimits | AgentMessagePlan | AgentMessageTaskNotification | AgentMessageTaskProgress | AgentMessageHarnessNotice | AgentMessageCompaction | AgentMessageSubagentUserMessage | AgentMessageModelReport;
340
361
  /** Status block the agent emits to signal iteration completion or blockers. */
341
362
  export interface AgentStatus {
342
363
  summary: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-compose/sdk",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "description": "Client library for agent-compose — define agents, runtimes, and workflows, and invoke them against an agent-compose server.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -104,7 +104,7 @@ type DurableAgentMessage = Exclude<
104
104
  AgentMessage,
105
105
  { type: "text_delta" } | { type: "usage_delta" } | { type: "plan_limits" } | { type: "task_notification" }
106
106
  | { type: "task_progress" } | { type: "harness_notice" } | { type: "compaction" }
107
- | { type: "subagent_user_message" }
107
+ | { type: "subagent_user_message" } | { type: "model_report" }
108
108
  >;
109
109
 
110
110
  export function summarizeAgentMessage(msg: DurableAgentMessage): AgentMessageSummary {
@@ -497,7 +497,7 @@ export async function agentLoop<TResponse = unknown>(opts: AgentLoopOpts<TRespon
497
497
  if (msg.type === "text_delta" || msg.type === "usage_delta" || msg.type === "plan_limits"
498
498
  || msg.type === "task_notification" || msg.type === "task_progress"
499
499
  || msg.type === "harness_notice" || msg.type === "compaction"
500
- || msg.type === "subagent_user_message") continue;
500
+ || msg.type === "subagent_user_message" || msg.type === "model_report") continue;
501
501
  opts.onAgentEvent?.(iteration, msg);
502
502
  // Usage summaries carry the resolved model so the server can price
503
503
  // token rows per model without correlating back to agent.spawned.
package/src/client.ts CHANGED
@@ -25,6 +25,7 @@ import type {
25
25
  RequestAgentPauseOptions, RequestAgentPauseResponse,
26
26
  SendAgentMessageOptions, SendAgentMessageResponse,
27
27
  RunDetail, RunListEntry, ListRunsOptions, TimelineEvent, RunFundingResponse, RunStepUsageResponse, EventRow, ReportEventInput,
28
+ ListWorkflowActivityOptions, ListWorkflowRunsOptions, WorkflowActivityPage, WorkflowRunsPage, WorkflowActivityHead, WorkflowActivityRun,
28
29
  ListEventsOptions, ListEventsResult, RunArtifactRow, RunLogLine, ListRunLogsOptions,
29
30
  CancelRunResponse, ListSnapshotsOptions, SnapshotListResponse, SnapshotListEntry, RunSnapshotEntry,
30
31
  } from "./types/api-runs.js";
@@ -81,6 +82,8 @@ export type {
81
82
  ResumePauseOptions, RequestAgentPauseOptions, AnswerSteerOptions, RequestAgentPauseResponse,
82
83
  SendAgentMessageOptions, SendAgentMessageResponse,
83
84
  RunDetail, RunListEntry, ListRunsOptions, TimelineEvent,
85
+ RunStartedBy, WorkflowActivityRun, WorkflowActivityHead, ListWorkflowActivityOptions, ListWorkflowRunsOptions,
86
+ WorkflowActivityPage, WorkflowRunsPage,
84
87
  FundingLane, RunFundingStamp, RunFundingUsageRow, RunFundingResponse,
85
88
  RunStepUsage, RunStepUsageResponse,
86
89
  EventSubjectType, EventRow, RunArtifactRow, ReportEventInput, ListEventsOptions, ListEventsResult,
@@ -123,7 +126,7 @@ export type {
123
126
  RefreshProjectObjectResult,
124
127
  ProjectStatus, ProjectStatusThread, ProjectStatusTask, ProjectStatusPerson, ProjectStatusWorker, ProjectStatusActivity,
125
128
  ProjectStatusActivityKind, ProjectStatusWaitingOn, ProjectStatusWaitingCount, ProjectStatusCounts,
126
- ThreadStatus, ThreadStatusWorker, ThreadStatusWorkerState, ThreadStatusWorkerEffort, ThreadStatusTodo, ThreadStatusDirector, ThreadStatusOutput, ThreadStatusEvent, ChatWork, ChatWorkThread,
129
+ ThreadStatus, ThreadStatusWorker, ThreadStatusWorkerState, ThreadStatusWorkerEffort, WorkerFunding, ThreadStatusTodo, ThreadStatusDirector, ThreadStatusOutput, ThreadStatusEvent, ChatWork, ChatWorkThread,
127
130
  ThreadStatusWaitingOn, ThreadStatusAssignee, ThreadStatusTodoActivity, ChatTodoPatch, ChatTodoComment,
128
131
  MeStatus, MeStatusCounts,
129
132
  } from "./types/api-projects.js";
@@ -681,6 +684,38 @@ export class AgentComposeClient {
681
684
  return body.workflows;
682
685
  }
683
686
 
687
+ /** A space's workflow activity: one stack per workflow of the space's own
688
+ * that has run there in the last 90 days — or, with `q`, that has a run
689
+ * matching the search, however old — the most recently run first, each
690
+ * with its latest (matching) run and what started it. The platform's
691
+ * default workflows (dynamic-task, repo-ingest, …) are left out, the
692
+ * search included. Paged by `cursor`. */
693
+ async listWorkflowActivity(opts: ListWorkflowActivityOptions = {}): Promise<WorkflowActivityPage> {
694
+ const q = new URLSearchParams();
695
+ if (opts.limit !== undefined) q.set("limit", String(opts.limit));
696
+ if (opts.cursor) q.set("cursor", opts.cursor);
697
+ if (opts.q) q.set("q", opts.q);
698
+ const slug = encodeURIComponent(opts.factorySlug ?? "default");
699
+ const body = await this.fetch<{ workflows: WorkflowActivityHead[]; has_more: boolean; next_cursor: string | null }>(
700
+ `/api/v1/factories/${slug}/workflow-activity${q.toString() ? `?${q}` : ""}`);
701
+ return { workflows: body.workflows, hasMore: body.has_more, nextCursor: body.next_cursor };
702
+ }
703
+
704
+ /** One workflow's runs in a space, newest first, by its exact registered
705
+ * name (`listRuns`' `workflow` is a substring match): the last 90 days,
706
+ * or with `q` every run matching the search; a platform default's name
707
+ * answers with no runs. Paged by `cursor`. */
708
+ async listWorkflowRuns(opts: ListWorkflowRunsOptions): Promise<WorkflowRunsPage> {
709
+ const q = new URLSearchParams({ workflow: opts.workflow });
710
+ if (opts.limit !== undefined) q.set("limit", String(opts.limit));
711
+ if (opts.cursor) q.set("cursor", opts.cursor);
712
+ if (opts.q) q.set("q", opts.q);
713
+ const slug = encodeURIComponent(opts.factorySlug ?? "default");
714
+ const body = await this.fetch<{ runs: WorkflowActivityRun[]; has_more: boolean; next_cursor: string | null }>(
715
+ `/api/v1/factories/${slug}/workflow-activity/runs?${q}`);
716
+ return { runs: body.runs, hasMore: body.has_more, nextCursor: body.next_cursor };
717
+ }
718
+
684
719
  /** Ordered lifecycle timeline for one run. */
685
720
  async getRunTimeline(runId: string, opts?: { limit?: number; offset?: number }): Promise<TimelineEvent[]> {
686
721
  const q = new URLSearchParams();
package/src/index.ts CHANGED
@@ -108,6 +108,7 @@ export type {
108
108
  AgentMessageHarnessNotice,
109
109
  AgentMessageCompaction,
110
110
  AgentMessageSubagentUserMessage,
111
+ AgentMessageModelReport,
111
112
  AgentStatus,
112
113
  } from "./types/protocol.js";
113
114
 
@@ -133,6 +134,8 @@ export type {
133
134
  EventSubjectType, EventRow, ReportEventInput, ListEventsOptions, ListEventsResult,
134
135
  RunLogLine, ListRunLogsOptions,
135
136
  RunListEntry, ListRunsOptions, RunDetail,
137
+ RunStartedBy, WorkflowActivityRun, WorkflowActivityHead, ListWorkflowActivityOptions, ListWorkflowRunsOptions,
138
+ WorkflowActivityPage, WorkflowRunsPage,
136
139
  FundingLane, RunFundingStamp, RunFundingUsageRow, RunFundingResponse,
137
140
  RunStepUsage, RunStepUsageResponse,
138
141
  RegisteredRuntime, RunState, RunStatus, FactoryRow, SnapshotListEntry, SnapshotListResponse,
@@ -187,7 +190,7 @@ export type {
187
190
  RefreshProjectObjectResult,
188
191
  ProjectStatus, ProjectStatusThread, ProjectStatusTask, ProjectStatusPerson, ProjectStatusWorker, ProjectStatusActivity,
189
192
  ProjectStatusActivityKind, ProjectStatusWaitingOn, ProjectStatusWaitingCount, ProjectStatusCounts,
190
- ThreadStatus, ThreadStatusWorker, ThreadStatusWorkerState, ThreadStatusWorkerEffort, ThreadStatusTodo, ThreadStatusDirector, ThreadStatusOutput, ThreadStatusEvent,
193
+ ThreadStatus, ThreadStatusWorker, ThreadStatusWorkerState, ThreadStatusWorkerEffort, WorkerFunding, ThreadStatusTodo, ThreadStatusDirector, ThreadStatusOutput, ThreadStatusEvent,
191
194
  ThreadStatusWaitingOn, ThreadStatusAssignee, ThreadStatusTodoActivity, ChatTodoPatch, ChatTodoComment,
192
195
  ChatWork, ChatWorkThread,
193
196
  MeStatus, MeStatusCounts,
@@ -443,6 +443,15 @@ export function wrapMidTurnUserMessage(text: string, opts?: MidTurnEnvelopeOptio
443
443
  // The thread agent that owns this worker, in its own words (owner decision
444
444
  // 2026-09-27): not the session user either. The row's own text closes with
445
445
  // its trust frame.
446
+ // A PLATFORM notice posted to wake this conversation (a credential
447
+ // delivered while the turn ran, prod 2026-10-05): nobody's message, so
448
+ // neither "the user" nor an agent is named, and the close asks for the
449
+ // act the notice calls for rather than an answer to a person.
450
+ if (opts?.platformNotice) {
451
+ return "The platform posted a notice in this conversation while you were working:\n\n"
452
+ + text
453
+ + "\n\nAct on it as you continue this turn.";
454
+ }
446
455
  const head = relayedFrom
447
456
  ? `A message relaying ${relayedFrom}'s own words arrived while you were working:\n\n`
448
457
  : opts?.fromOwnerAgent
@@ -456,10 +465,13 @@ export function wrapMidTurnUserMessage(text: string, opts?: MidTurnEnvelopeOptio
456
465
  /** Who a mid-turn message speaks for, when it is not the session user.
457
466
  * `relayedFrom` = the display name of the person whose own words an agent
458
467
  * relayed verbatim; `fromOwnerAgent` = the thread agent that owns this
459
- * worker, in its own words; both absent = the session user's own message. */
468
+ * worker, in its own words; `platformNotice` = a system notice the
469
+ * platform posted to wake the conversation (nobody's words); all absent =
470
+ * the session user's own message. */
460
471
  export interface MidTurnEnvelopeOptions {
461
472
  relayedFrom?: string | null;
462
473
  fromOwnerAgent?: boolean;
474
+ platformNotice?: boolean;
463
475
  }
464
476
 
465
477
  /** The one delivery-ack exec `injectUserMessage` runs: append the message
@@ -0,0 +1,24 @@
1
+ /**
2
+ * A model id as a harness names it — the one derivation behind every
3
+ * `model_report` the Claude runtimes emit (AgentMessageModelReport): the
4
+ * `model` on claude-code's `system`/`init` event and the `message.model` on
5
+ * each `assistant` event, which the Agent SDK's messages mirror.
6
+ *
7
+ * - claude-code's `[1m]`-style suffix (`claude-opus-4-8[1m]`) is the CLI's
8
+ * context-window marker: a variant flag on the same model, not another
9
+ * model, so the report drops it;
10
+ * - `<synthetic>` is the harness's own voice (slash-command stdout,
11
+ * advisories) and names no model;
12
+ * - anything that is not a non-empty string names none.
13
+ *
14
+ * Machine-format rules only; nothing here reads words.
15
+ */
16
+
17
+ const MODEL_ID_MAX = 200;
18
+
19
+ export function reportedModelId(raw: unknown): string | undefined {
20
+ if (typeof raw !== "string") return undefined;
21
+ const id = raw.replace(/\[[^\]]*\]$/, "").trim();
22
+ if (id.length === 0 || id === "<synthetic>") return undefined;
23
+ return id.length > MODEL_ID_MAX ? id.slice(0, MODEL_ID_MAX) : id;
24
+ }
@@ -40,6 +40,7 @@ import type {
40
40
  WorkflowProgressEntry,
41
41
  } from "../index.js";
42
42
  import { createCliAgentRuntime, shellQuote, type CliAgentSpec, type CliReasoningEffort } from "./_cli-agent.js";
43
+ import { reportedModelId } from "./_reported-model.js";
43
44
  import { formatError } from "../utils/errors.js";
44
45
  import { CLAUDE_CODE_VERSION } from "../sandbox/baked-clis.js";
45
46
 
@@ -668,7 +669,13 @@ export const claudeCodeSpec: CliAgentSpec = {
668
669
  // Structural marker only — no content sniffing.
669
670
  const synthetic = message?.model === "<synthetic>";
670
671
  const blocks = Array.isArray(message?.content) ? message.content : [];
671
- return blocks.flatMap((b): AgentMessage[] => {
672
+ // The model the API answered with, named on every assistant event
673
+ // (AgentMessageModelReport): the truth after a /model switch or a
674
+ // fallback. Top level only — a subagent's events name the
675
+ // subagent's model, not the worker's; `<synthetic>` names none.
676
+ const model = parentId ? undefined : reportedModelId(message?.model);
677
+ const report: AgentMessage[] = model ? [{ type: "model_report", model, timestamp: ts }] : [];
678
+ return report.concat(blocks.flatMap((b): AgentMessage[] => {
672
679
  if (b.type === "text" && typeof b.text === "string" && b.text.length > 0) {
673
680
  return [{ type: synthetic ? "harness_notice" : "text", text: b.text, timestamp: ts }];
674
681
  }
@@ -682,7 +689,7 @@ export const claudeCodeSpec: CliAgentSpec = {
682
689
  }];
683
690
  }
684
691
  return [];
685
- });
692
+ }));
686
693
  }
687
694
  // User API message: the CLI echoes tool results back as user content,
688
695
  // and injects `<task-notification>` blocks (background-task completion
@@ -802,7 +809,9 @@ export const claudeCodeSpec: CliAgentSpec = {
802
809
  const limits = parsePlanLimits(p, ts);
803
810
  return limits ? [limits] : [];
804
811
  }
805
- // System events: init carries the session id (extractSessionId), and
812
+ // System events: init carries the session id (extractSessionId) and
813
+ // the session's resolved model (the first model report of the turn;
814
+ // the assistant events confirm or change it), and
806
815
  // the background-task lane rides here too — `task_notification` is
807
816
  // the completion evidence stream-json actually emits (see the section
808
817
  // header above), and `task_progress` the LIVE background-task feed
@@ -814,6 +823,10 @@ export const claudeCodeSpec: CliAgentSpec = {
814
823
  // under system (task_started, task_updated, background_tasks_changed,
815
824
  // thinking_tokens) is lifecycle noise here.
816
825
  case "system": {
826
+ if (p.subtype === "init") {
827
+ const model = reportedModelId(p.model);
828
+ return model ? [{ type: "model_report", model, timestamp: ts }] : [];
829
+ }
817
830
  if (p.subtype === "task_progress") {
818
831
  const progress = parseSystemTaskProgress(p, ts);
819
832
  return progress ? [progress] : [];
@@ -9,6 +9,7 @@ import { runProcessorChain } from "../processors/runner.js";
9
9
  import type { ProcessorContext, ToolCall } from "../processors/processor.js";
10
10
  import { RequestContext } from "../request-context/request-context.js";
11
11
  import { boundProcessorPause } from "../pause/pause-core.js";
12
+ import { reportedModelId } from "./_reported-model.js";
12
13
  import { formatError } from "../utils/errors.js";
13
14
 
14
15
  function now(): string { return new Date().toISOString(); }
@@ -19,11 +20,17 @@ function translateMessage(message: Record<string, unknown>): AgentMessage[] {
19
20
 
20
21
  if (message.type === "system" && message.subtype === "init") {
21
22
  msgs.push({ type: "init", sessionId: String(message.session_id ?? ""), timestamp: ts });
23
+ // The session's resolved model, as the harness names it
24
+ // (AgentMessageModelReport); the assistant messages confirm or change it.
25
+ const model = reportedModelId(message.model);
26
+ if (model) msgs.push({ type: "model_report", model, timestamp: ts });
22
27
  return msgs;
23
28
  }
24
29
 
25
30
  if (message.type === "assistant") {
26
- const raw = message.message as { content?: unknown[] } | undefined;
31
+ const raw = message.message as { content?: unknown[]; model?: unknown } | undefined;
32
+ const model = typeof message.parent_tool_use_id === "string" ? undefined : reportedModelId(raw?.model);
33
+ if (model) msgs.push({ type: "model_report", model, timestamp: ts });
27
34
  for (const block of raw?.content ?? []) {
28
35
  const b = block as Record<string, unknown>;
29
36
  if (b.type === "text") msgs.push({ type: "text", text: String(b.text ?? ""), timestamp: ts });
@@ -102,6 +102,18 @@ export interface RegisterWorkflowInput {
102
102
  factoryDrive?: "required" | "none";
103
103
  /** Factory slug. Defaults to `"default"`. */
104
104
  factorySlug?: string;
105
+ /** Register INTO a project (`agentc register --project`, ADR-0087): the
106
+ * workflow, its schedules and its runs are visible to the project's
107
+ * members alone, read live, so leaving the project loses them — the
108
+ * registrant included (the workflow belongs to the project, with no
109
+ * personal owner). Any member with a write or owner seat in the project
110
+ * may register into it on a key that holds `invoke`; the `manage` scope
111
+ * is not needed. A read seat is refused (403 `role_read_only`); a
112
+ * project the registrant cannot see answers 404 exactly as one that does
113
+ * not exist. Omitted, a registration from a terminal or an API key is
114
+ * the whole space's and takes `manage` (403 `manage_required`
115
+ * otherwise). */
116
+ projectId?: string;
105
117
  }
106
118
 
107
119
  export interface TemplateRow {
@@ -332,6 +344,8 @@ export interface UpdateFactoryInput {
332
344
 
333
345
  export interface ScheduleRow {
334
346
  id: string;
347
+ /** The factory the schedule (and the workflow it fires) lives in. */
348
+ factoryId: string;
335
349
  name: string;
336
350
  workflowName: string;
337
351
  cron: string;
@@ -401,9 +415,14 @@ export interface SessionSecretRequestCreated {
401
415
  * open ask's link already went out and nothing new exists to send. */
402
416
  url: string | null;
403
417
  expiresAt: string;
404
- /** True = a standing auto-approve set already filled the request at the
405
- * mint — nothing is pending; source the session env now. */
418
+ /** True = a standing auto-approve set or this work's grant already filled
419
+ * the request at the mint — nothing is pending. */
406
420
  autoApproved?: boolean;
421
+ /** With autoApproved: true = the values are on the session's RUNNING
422
+ * machine now (its env file, and its egress ruleset for a brokered key),
423
+ * so re-sourcing the session env loads them; false = no machine is
424
+ * running or the push failed, and they land when the next turn starts. */
425
+ loaded?: boolean;
407
426
  /** Set with autoApproved when the grant came from this work's earlier
408
427
  * worker (the same person's grant, carried with no card): who gave it. */
409
428
  carried?: { grantedByName: string | null };
@@ -193,10 +193,20 @@ export interface ProjectStatusWaitingOn {
193
193
  who: string;
194
194
  /** What they will do or answer, in the people's terms. */
195
195
  what: string | null;
196
- kind: "task" | "question";
196
+ /** `task`: a plan task waiting on a person; `question`: a worker's
197
+ * question owed an answer; `answer`: the thread's own question to a
198
+ * person (its raise declared whom it waits on), open until one of them
199
+ * answers where Ivy spoke. */
200
+ kind: "task" | "question" | "answer";
197
201
  /** The chat message where the person said it, when the thread agent
198
- * recorded one: the way to the ask. Null otherwise. */
202
+ * recorded one, or Ivy's message carrying the thread's question: the way
203
+ * to the ask. Null otherwise. */
199
204
  messageId: string | null;
205
+ /** An answer wait's place: the chat thread Ivy spoke in (null for the
206
+ * room's top level). Absent on the other kinds. */
207
+ threadRootId?: string | null;
208
+ /** When the thread asked (ISO). Absent on the other kinds. */
209
+ at?: string | null;
200
210
  }
201
211
 
202
212
  /** Whom a TASK waits on (owner 2026-10-05: a todo may wait on more than one
@@ -342,6 +352,15 @@ export type ThreadStatusWorkerState = "starting" | "working" | "done" | "failed"
342
352
  /** The effort a worker was started with; null = the harness's own default. */
343
353
  export type ThreadStatusWorkerEffort = "low" | "medium" | "high" | "xhigh" | "max";
344
354
 
355
+ /** What pays for a worker's inference, as its hover card says it (owner
356
+ * 2026-10-05: a findable detail, never a mark on rows): a person's connected
357
+ * plan (the person by id and name only, when the turn named them), platform
358
+ * credits, or a connected provider key by its provider family. */
359
+ export type WorkerFunding =
360
+ | { lane: "subscription"; owner: { id: string; name: string | null } | null }
361
+ | { lane: "platform" }
362
+ | { lane: "byok"; provider: string };
363
+
345
364
  export interface ThreadStatusWorker {
346
365
  /** The worker's session (its page is /conversations/:id). */
347
366
  conversationId: string;
@@ -356,8 +375,17 @@ export interface ThreadStatusWorker {
356
375
  result: string | null;
357
376
  /** The question it is parked on, while one is owed. */
358
377
  asking: string | null;
359
- /** The model stamped at birth; null = the runtime's own default. */
378
+ /** The model stamped at birth (what it was CONFIGURED to run); null =
379
+ * the runtime's own default. */
360
380
  model: string | null;
381
+ /** The models its turns ACTUALLY ran (owner 2026-10-06: "what model
382
+ * actually did the work"), each once in first-seen order — a mid-turn
383
+ * switch lists both: the harness's own report (its stream; codex's
384
+ * rollout file read at the turn's end), then the metering gateway's
385
+ * attested record of the model each platform-funded call went to. Never
386
+ * derived from `model`: empty when nothing is on record, and the
387
+ * surfaces then say the model isn't known. Absent on older servers. */
388
+ ranModels?: string[];
361
389
  effort: ThreadStatusWorkerEffort | null;
362
390
  /** The harness it runs ("claude-code", "codex", ...); null when unknown. */
363
391
  runtime: string | null;
@@ -366,11 +394,17 @@ export interface ThreadStatusWorker {
366
394
  executor: "local" | "cloud" | null;
367
395
  /** When its running turn started (ISO); null while no turn runs. */
368
396
  workingSince: string | null;
397
+ /** When its newest turn ended (ISO): the moment it stopped, while no turn
398
+ * runs. Null while a turn runs, and for a worker that has not run one. */
399
+ lastTurnEndedAt: string | null;
369
400
  /** Its machine has a live desktop to show (the Desktop pill's own
370
401
  * verdict, for the session's current machine): the chat draws a door to
371
402
  * it on the step the worker is on. False for a local session, a machine
372
403
  * with no GUI, or a session no longer on a machine. */
373
404
  desktopCapable: boolean;
405
+ /** What pays for it, when the record says (see WorkerFunding); null when
406
+ * nothing is on record. Absent on older servers. */
407
+ funding?: WorkerFunding | null;
374
408
  }
375
409
 
376
410
  /** A message that directed a step: who wrote it and the opening of what
@@ -339,6 +339,74 @@ export interface ListRunsOptions {
339
339
  limit?: number;
340
340
  }
341
341
 
342
+ /** What started a run (`GET /factories/:slug/workflow-activity*`), read off
343
+ * the dispatch stamps: a schedule's tick, a thread's scripted check, the
344
+ * chat an agent's turn dispatched it from, the person who invoked it from
345
+ * the dashboard, or the API key (the CLI, a script). */
346
+ export type RunStartedBy =
347
+ | { kind: "schedule"; name: string | null }
348
+ | { kind: "check" }
349
+ | { kind: "chat"; conversationId: string; title: string | null }
350
+ | { kind: "person"; userId: string; name: string; image: string | null; avatarUrl: string | null }
351
+ | { kind: "key"; name: string }
352
+ | { kind: "unknown" };
353
+
354
+ /** One run in a space's workflow activity: the runs list's summary plus
355
+ * what started it. */
356
+ export interface WorkflowActivityRun extends RunListEntry {
357
+ finalSummary: string | null;
358
+ /** Structured return value from the workflow, when it completed. */
359
+ output: unknown;
360
+ startedBy: RunStartedBy;
361
+ }
362
+
363
+ /** One stack in a space's workflow activity: a workflow that has run there
364
+ * and its latest run. */
365
+ export interface WorkflowActivityHead {
366
+ workflow: string;
367
+ latestRun: WorkflowActivityRun;
368
+ }
369
+
370
+ export interface ListWorkflowActivityOptions {
371
+ /** Factory the runs live in. Defaults to "default". */
372
+ factorySlug?: string;
373
+ /** Stacks per page (1–50, server default 20). */
374
+ limit?: number;
375
+ /** The previous page's `nextCursor`. */
376
+ cursor?: string;
377
+ /** A search (at most 100 characters): every run whose workflow name,
378
+ * title, failure or summary contains it, without case — reaching past
379
+ * the last 90 days the listing shows without one. */
380
+ q?: string;
381
+ }
382
+
383
+ export interface ListWorkflowRunsOptions {
384
+ /** Factory the runs live in. Defaults to "default". */
385
+ factorySlug?: string;
386
+ /** The registered workflow name, exactly. */
387
+ workflow: string;
388
+ /** Runs per page (1–50, server default 10). */
389
+ limit?: number;
390
+ /** The previous page's `nextCursor`. */
391
+ cursor?: string;
392
+ /** A search (at most 100 characters): the workflow's runs whose title,
393
+ * failure or summary contains it, without case — reaching past the last
394
+ * 90 days the listing shows without one. */
395
+ q?: string;
396
+ }
397
+
398
+ export interface WorkflowActivityPage {
399
+ workflows: WorkflowActivityHead[];
400
+ hasMore: boolean;
401
+ nextCursor: string | null;
402
+ }
403
+
404
+ export interface WorkflowRunsPage {
405
+ runs: WorkflowActivityRun[];
406
+ hasMore: boolean;
407
+ nextCursor: string | null;
408
+ }
409
+
342
410
  export interface TimelineEvent {
343
411
  kind: string;
344
412
  at: string;
@@ -334,6 +334,28 @@ export interface AgentMessageSubagentUserMessage extends AgentMessageBase {
334
334
  parentToolUseId: string;
335
335
  }
336
336
 
337
+ /** The harness's OWN report of the model it is running — never the
338
+ * platform's configuration (owner 2026-10-06: "It's very difficult to
339
+ * tell which model did this work"). claude-code names it twice: once on
340
+ * `system`/`init` (`model`, the session's resolved model) and on every
341
+ * top-level `assistant` event (`message.model`, the id the API answered
342
+ * with — the truth after a `/model` switch or a fallback; `<synthetic>`
343
+ * is the harness's own voice and names none; a subagent's events name the
344
+ * subagent's model, not the worker's, and are left out). The normaliser
345
+ * emits one report per naming, so a consumer that stamps the turn's
346
+ * models dedupes in order of first appearance and keeps every distinct
347
+ * id (a mid-turn switch records both). codex's `exec --json` events and
348
+ * opencode's `run --format json` lines carry no model at all (verified
349
+ * against both sources, 2026-10-06): those harnesses emit none, and the
350
+ * record stays honestly empty. Additive kind: existing producers never
351
+ * emit it. */
352
+ export interface AgentMessageModelReport extends AgentMessageBase {
353
+ type: "model_report";
354
+ /** The model id as the harness reports it, minus claude-code's
355
+ * `[1m]`-style context-window marker (runtimes/_reported-model.ts). */
356
+ model: string;
357
+ }
358
+
337
359
  export type AgentMessage =
338
360
  | AgentMessageInit
339
361
  | AgentMessageText
@@ -351,7 +373,8 @@ export type AgentMessage =
351
373
  | AgentMessageTaskProgress
352
374
  | AgentMessageHarnessNotice
353
375
  | AgentMessageCompaction
354
- | AgentMessageSubagentUserMessage;
376
+ | AgentMessageSubagentUserMessage
377
+ | AgentMessageModelReport;
355
378
 
356
379
  /** Status block the agent emits to signal iteration completion or blockers. */
357
380
  export interface AgentStatus {