novoagents 0.3.0-alpha.21 → 0.3.0-alpha.23

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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ Internal engine, routing, and infrastructure changes are intentionally omitted.
5
5
 
6
6
  ## Unreleased
7
7
 
8
+ ## 0.3.0-alpha.23 - 2026-06-18
9
+
10
+ - Planning is now always on for every agent. Remove
11
+ `capabilities.planning` from agent configs; `update_plan` tool calls still
12
+ stream with `category: 'planning'`.
13
+
14
+ ## 0.3.0-alpha.22 - 2026-06-18
15
+
16
+ - Added HTTP connections for registering OpenAPI-backed tools through
17
+ `novo.httpConnections` and attaching them with
18
+ `capabilities.http.connectionIds`.
19
+ - Runs can now declare `outputSchema`; structured final values surface on
20
+ `data-novo-terminal.output` and `RunFinalResult.output`.
21
+ - Disabled, missing, or policy-denied HTTP connections now emit
22
+ `data-novo-http-connection-unavailable` and use stable
23
+ `http_connection_not_found` / `policy_denied` errors.
24
+ - Public shell tool names are now canonicalized to `bash` across stream chunks,
25
+ approval hooks, event sinks, and run resources. The capability key remains
26
+ `terminal.run`; customer policy should branch on public `toolName: 'bash'`.
27
+
8
28
  ## 0.3.0-alpha.21 - 2026-06-18
9
29
 
10
30
  - Subagent task display text is now consistently framed as a `label` rather
package/README.md CHANGED
@@ -78,7 +78,7 @@ Type guards are exported for every Novo-specific chunk
78
78
  `isNovoToolApprovalRequested`, `isNovoUserInteractionRequested`,
79
79
  `isNovoToolCall`, `isNovoToolResultOverflow`, `isNovoWorkspace`,
80
80
  `isNovoBrowserSession`, and the rest of the `data-novo-*` stream taxonomy).
81
- Public `toolName` fields are Novo canonical names such as `terminal_run`; branch
81
+ Public `toolName` fields are Novo canonical names such as `bash`; branch
82
82
  on those stable values in your UI and approval policy.
83
83
  `readNovoToolError(event)` recognizes both AI SDK `tool-output-error` chunks and
84
84
  returned `{ type: 'tool-output-error', ... }` payloads inside
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AgentsNamespace, ArtifactsNamespace, BrowserSessionsNamespace, EnvironmentsNamespace, EventSinksNamespace, FilesNamespace, GithubConnectionsNamespace, ResultHandlersNamespace, RunsNamespace, InteractionsNamespace, SecretContextsNamespace, SecretsNamespace, ThreadsNamespace, ToolApprovalHooksNamespace, ToolServersNamespace, UsageNamespace, BandsNamespace } from './types.js';
1
+ import type { AgentsNamespace, ArtifactsNamespace, BrowserSessionsNamespace, EnvironmentsNamespace, EventSinksNamespace, FilesNamespace, GithubConnectionsNamespace, ResultHandlersNamespace, RunsNamespace, InteractionsNamespace, SecretContextsNamespace, SecretsNamespace, ThreadsNamespace, ToolApprovalHooksNamespace, ToolServersNamespace, HttpConnectionsNamespace, UsageNamespace, BandsNamespace } from './types.js';
2
2
  export type RequestOptions = {
3
3
  method?: string;
4
4
  path: string;
@@ -38,5 +38,6 @@ export declare function createSecretsNamespace(client: NovoHttpClient): SecretsN
38
38
  export declare function createSecretContextsNamespace(client: NovoHttpClient): SecretContextsNamespace;
39
39
  export declare function createGithubConnectionsNamespace(client: NovoHttpClient): GithubConnectionsNamespace;
40
40
  export declare function createToolServersNamespace(client: NovoHttpClient): ToolServersNamespace;
41
+ export declare function createHttpConnectionsNamespace(client: NovoHttpClient): HttpConnectionsNamespace;
41
42
  export declare function createUsageNamespace(client: NovoHttpClient): UsageNamespace;
42
43
  export declare function createBandsNamespace(client: NovoHttpClient): BandsNamespace;
package/dist/client.js CHANGED
@@ -687,6 +687,46 @@ export function createToolServersNamespace(client) {
687
687
  },
688
688
  };
689
689
  }
690
+ export function createHttpConnectionsNamespace(client) {
691
+ return {
692
+ register(input) {
693
+ return client.json({
694
+ method: 'POST',
695
+ path: '/v1/http-connections',
696
+ body: input,
697
+ });
698
+ },
699
+ list() {
700
+ return client.json({
701
+ path: '/v1/http-connections',
702
+ });
703
+ },
704
+ get(httpConnectionId) {
705
+ return client.json({
706
+ path: `/v1/http-connections/${encodeURIComponent(httpConnectionId)}`,
707
+ });
708
+ },
709
+ update(httpConnectionId, input) {
710
+ return client.json({
711
+ method: 'PATCH',
712
+ path: `/v1/http-connections/${encodeURIComponent(httpConnectionId)}`,
713
+ body: input,
714
+ });
715
+ },
716
+ delete(httpConnectionId) {
717
+ return client.json({
718
+ method: 'DELETE',
719
+ path: `/v1/http-connections/${encodeURIComponent(httpConnectionId)}`,
720
+ });
721
+ },
722
+ test(httpConnectionId) {
723
+ return client.json({
724
+ method: 'POST',
725
+ path: `/v1/http-connections/${encodeURIComponent(httpConnectionId)}/test`,
726
+ });
727
+ },
728
+ };
729
+ }
690
730
  function credentialListPath(path, input) {
691
731
  const params = new URLSearchParams();
692
732
  if (input.limit !== undefined)
package/dist/errors.d.ts CHANGED
@@ -9,7 +9,7 @@ export type NovoErrorType = 'invalid_request_error' | 'authentication_error' | '
9
9
  * `apps/cloud/lib/http/errors.ts` — extend in lockstep when the cloud adds
10
10
  * new error codes.
11
11
  */
12
- export type NovoErrorCode = 'invalid_api_key' | 'permission_denied' | 'agent_not_found' | 'artifact_not_found' | 'browser_session_not_found' | 'file_not_found' | 'file_not_ready' | 'file_too_large' | 'environment_not_found' | 'event_sink_not_found' | 'github_connection_not_found' | 'result_handler_not_found' | 'result_handler_invalid_kind' | 'result_handler_secret_missing' | 'secret_not_found' | 'secret_context_not_found' | 'thread_not_found' | 'tool_server_not_found' | 'tool_approval_hook_not_found' | 'interaction_not_found' | 'run_not_found' | 'worker_not_found' | 'invalid_request_error' | 'invalid_status' | 'invalid_createdSince' | 'invalid_limit' | 'invalid_email' | 'invalid_workspace_config' | 'strict_data_handling_unavailable' | 'thread_busy' | 'run_not_active' | 'idempotency_key_conflict' | 'name_conflict' | 'resource_in_use' | 'quota_exceeded' | 'rate_limited' | 'insufficient_quota' | 'per_run_cap_exceeded' | 'budget_exceeded' | 'max_steps_exceeded' | 'max_duration_exceeded' | 'step_duration_exceeded' | 'workspace_unavailable' | 'data_handling_unavailable' | 'attachment_unsupported_for_agent_configuration' | 'pricing_unavailable' | 'service_unavailable' | 'invalid_response' | 'internal_error' | 'upstream_provider_error' | 'upstream_unavailable' | 'web_runtime_unconfigured' | 'artifact_storage_unconfigured' | 'tools_changed' | 'audio_generation_unconfigured' | 'video_generation_unconfigured' | 'media_analysis_unconfigured' | 'managed_browser_unconfigured' | 'managed_document_processing_unconfigured' | 'managed_media_editing_unconfigured' | 'managed_github_unconfigured' | 'github_connection_test_failed' | 'cannot_modify_self' | 'last_admin_protected' | 'member_not_found' | 'invitation_not_found' | 'already_member' | 'already_invited';
12
+ export type NovoErrorCode = 'invalid_api_key' | 'permission_denied' | 'agent_not_found' | 'artifact_not_found' | 'browser_session_not_found' | 'file_not_found' | 'file_not_ready' | 'file_too_large' | 'environment_not_found' | 'event_sink_not_found' | 'github_connection_not_found' | 'http_connection_not_found' | 'result_handler_not_found' | 'result_handler_invalid_kind' | 'result_handler_secret_missing' | 'secret_not_found' | 'secret_context_not_found' | 'thread_not_found' | 'tool_server_not_found' | 'tool_approval_hook_not_found' | 'interaction_not_found' | 'run_not_found' | 'worker_not_found' | 'invalid_request_error' | 'invalid_status' | 'invalid_createdSince' | 'invalid_limit' | 'invalid_email' | 'invalid_workspace_config' | 'strict_data_handling_unavailable' | 'thread_busy' | 'run_not_active' | 'idempotency_key_conflict' | 'name_conflict' | 'resource_in_use' | 'quota_exceeded' | 'rate_limited' | 'insufficient_quota' | 'per_run_cap_exceeded' | 'budget_exceeded' | 'max_steps_exceeded' | 'max_duration_exceeded' | 'step_duration_exceeded' | 'workspace_unavailable' | 'data_handling_unavailable' | 'attachment_unsupported_for_agent_configuration' | 'pricing_unavailable' | 'service_unavailable' | 'invalid_response' | 'internal_error' | 'upstream_provider_error' | 'upstream_unavailable' | 'web_runtime_unconfigured' | 'artifact_storage_unconfigured' | 'tools_changed' | 'audio_generation_unconfigured' | 'video_generation_unconfigured' | 'media_analysis_unconfigured' | 'managed_browser_unconfigured' | 'managed_document_processing_unconfigured' | 'managed_media_editing_unconfigured' | 'managed_github_unconfigured' | 'github_connection_test_failed' | 'cannot_modify_self' | 'last_admin_protected' | 'member_not_found' | 'invitation_not_found' | 'already_member' | 'already_invited';
13
13
  type ErrorPayload = {
14
14
  type: NovoErrorType | (string & {});
15
15
  code: NovoErrorCode | (string & {});
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AgentsNamespace, ArtifactsNamespace, BandsNamespace, BrowserSessionsNamespace, EnvironmentsNamespace, EventSinksNamespace, FilesNamespace, GithubConnectionsNamespace, InteractionsNamespace, NovoAgentsOptions, ResultHandlersNamespace, RunsNamespace, SecretContextsNamespace, SecretsNamespace, ThreadsNamespace, ToolApprovalHooksNamespace, ToolServersNamespace, UsageNamespace } from './types.js';
1
+ import type { AgentsNamespace, ArtifactsNamespace, BandsNamespace, BrowserSessionsNamespace, EnvironmentsNamespace, EventSinksNamespace, FilesNamespace, GithubConnectionsNamespace, InteractionsNamespace, NovoAgentsOptions, ResultHandlersNamespace, RunsNamespace, SecretContextsNamespace, SecretsNamespace, ThreadsNamespace, ToolApprovalHooksNamespace, ToolServersNamespace, HttpConnectionsNamespace, UsageNamespace } from './types.js';
2
2
  export declare class NovoAgents {
3
3
  readonly apiKey: string;
4
4
  readonly baseUrl: string;
@@ -19,13 +19,14 @@ export declare class NovoAgents {
19
19
  readonly secrets: SecretsNamespace;
20
20
  readonly secretContexts: SecretContextsNamespace;
21
21
  readonly toolServers: ToolServersNamespace;
22
+ readonly httpConnections: HttpConnectionsNamespace;
22
23
  readonly usage: UsageNamespace;
23
24
  readonly bands: BandsNamespace;
24
25
  private readonly client;
25
26
  constructor(options?: NovoAgentsOptions);
26
27
  }
27
- export type { Agent, AgentApprovals, AgentArtifacts, AgentCapabilities, AgentCreatePolicies, AgentFile, AgentFileUpload, Artifact, ArtifactKind, AgentEventsInput, AgentInput, AgentInputAttachment, AgentPolicies, AgentPatchPolicies, AgentSkill, AgentWorkspace, MediaGenerationConfig, AgentWorkspaceNetwork, AgentWorkspaceResourcePreset, AgentWorkspaceSeed, AgentWorkspaceService, AgentsNamespace, ArtifactsNamespace, Band, BrowserCapabilityConfig, BrowserSessionLiveView, BrowserSessionsNamespace, CancelThreadResponse, CapabilityResolutionEntry, ResolvableCapability, ContextBlock, ContextInput, CredentialListInput, DataHandling, DeleteAgentResponse, DeleteThreadResponse, Environment, EnvironmentsNamespace, EventSink, EventSinksNamespace, FileCreateInput, FilesNamespace, GithubConnection, GithubConnectionOperation, GithubConnectionsNamespace, GithubConnectionTestResult, GithubMergeMethod, GithubMergePolicy, GithubRepositoryPolicy, Interaction, InteractionsNamespace, Metadata, MetadataPatch, ModelFinishReason, NovoAgentEvent, NovoAgentsOptions, NovoBrowserSessionChunk, NovoCompactionChunk, NovoDataChunk, NovoMessage, NovoMessagePart, NovoMessageRole, NovoRunMetaChunk, NovoStepTerminalChunk, NovoStreamChunk, NovoTaskChunk, NovoTerminalChunk, NovoTerminalReason, NovoToolCallChunk, NovoToolCallStatus, NovoToolCategory, NovoToolExecution, NovoToolApprovalRequestedChunk, NovoToolApprovalResolvedChunk, NovoToolResultOverflowChunk, NovoToolServerUnavailableChunk, NovoUsageChunk, NovoUserInteractionRequestedChunk, NovoUserInteractionResolvedChunk, NovoWorkerMetaChunk, NovoWorkerTerminalChunk, NovoWorkspaceChunk, Page, ProductEvent, ProductEventBatch, ProductEventType, ReconnectOptions, ResolveInteractionBody, ResultHandler, ResultHandlersNamespace, Run, RunError, RunFinalResult, RunReceipt, RunStartInput, RunStatus, RunStream, RunsListParams, RunsNamespace, StreamToCompletionOptions, BandInfo, BandsNamespace, Secret, SecretContext, SecretContextBinding, SecretContextTestResult, SecretContextsNamespace, SecretProjection, SecretSource, SecretsNamespace, StepStatus, StepTerminalOutput, Thread, ThreadWorkspaceStatus, ThreadWorkspaceSummary, ThreadsNamespace, ToolApprovalHook, ToolApprovalHookErrorPolicy, ToolApprovalHookRequest, ToolApprovalHookResponse, ToolApprovalHooksNamespace, ToolServer, ToolServerAuth, ToolServerTestResult, ToolServersNamespace, NovoToolErrorInfo, UsageAggregateRow, UsageEvent, UsageEventMeterKind, UsageEventResourceKind, UsageEventScope, UsageGroupBy, UsageNamespace, UsageTotal, UserInteractionAction, UserInteractionAnswer, UserInteractionOption, UserInteractionQuestion, UserInteractionRequestShape, UserInteractionResolution, WorkerStatus, WorkerStream, } from './types.js';
28
- export { isNovoBrowserSession, isNovoCompaction, isNovoRunMeta, isNovoStepTerminal, isNovoTask, isNovoTerminal, isNovoToolApprovalResolved, isNovoTextDelta, isNovoToolApprovalRequested, isNovoToolCall, isNovoToolError, isNovoToolOutput, isNovoToolResultOverflow, isNovoToolServerUnavailable, isNovoUsage, isNovoUserInteractionRequested, isNovoUserInteractionResolved, isNovoWorkerMeta, isNovoWorkerTerminal, isNovoWorkspace, readNovoToolError, } from './types.js';
28
+ export type { Agent, AgentApprovals, AgentArtifacts, AgentCapabilities, AgentCreatePolicies, AgentFile, AgentFileUpload, Artifact, ArtifactKind, AgentEventsInput, AgentInput, AgentInputAttachment, AgentPolicies, AgentPatchPolicies, AgentSkill, AgentWorkspace, MediaGenerationConfig, AgentWorkspaceNetwork, AgentWorkspaceResourcePreset, AgentWorkspaceSeed, AgentWorkspaceService, AgentsNamespace, ArtifactsNamespace, Band, BrowserCapabilityConfig, BrowserSessionLiveView, BrowserSessionsNamespace, CancelThreadResponse, CapabilityResolutionEntry, ResolvableCapability, ContextBlock, ContextInput, CredentialListInput, DataHandling, DeleteAgentResponse, DeleteThreadResponse, Environment, EnvironmentsNamespace, EventSink, EventSinksNamespace, FileCreateInput, FilesNamespace, GithubConnection, GithubConnectionOperation, GithubConnectionsNamespace, GithubConnectionTestResult, GithubMergeMethod, GithubMergePolicy, GithubRepositoryPolicy, Interaction, InteractionsNamespace, Metadata, MetadataPatch, ModelFinishReason, NovoAgentEvent, NovoAgentsOptions, NovoBrowserSessionChunk, NovoCompactionChunk, NovoDataChunk, NovoMessage, NovoMessagePart, NovoMessageRole, NovoRunMetaChunk, NovoStepTerminalChunk, NovoStreamChunk, NovoTaskChunk, NovoTerminalChunk, NovoTerminalReason, NovoToolCallChunk, NovoToolCallStatus, NovoToolCategory, NovoToolExecution, NovoToolApprovalRequestedChunk, NovoToolApprovalResolvedChunk, NovoToolResultOverflowChunk, NovoToolServerUnavailableChunk, NovoUsageChunk, NovoUserInteractionRequestedChunk, NovoUserInteractionResolvedChunk, NovoWorkerMetaChunk, NovoWorkerTerminalChunk, NovoWorkspaceChunk, Page, ProductEvent, ProductEventBatch, ProductEventType, ReconnectOptions, ResolveInteractionBody, ResultHandler, ResultHandlersNamespace, Run, RunError, RunFinalResult, RunReceipt, RunStartInput, RunStatus, RunStream, RunsListParams, RunsNamespace, StreamToCompletionOptions, BandInfo, BandsNamespace, Secret, SecretContext, SecretContextBinding, SecretContextTestResult, SecretContextsNamespace, SecretProjection, SecretSource, SecretsNamespace, StepStatus, StepTerminalOutput, Thread, ThreadWorkspaceStatus, ThreadWorkspaceSummary, ThreadsNamespace, ToolApprovalHook, ToolApprovalHookErrorPolicy, ToolApprovalHookRequest, ToolApprovalHookResponse, ToolApprovalHooksNamespace, ToolServer, ToolServerAuth, ToolServerTestResult, ToolServersNamespace, HttpConnection, HttpConnectionAuth, HttpConnectionTestResult, HttpConnectionsNamespace, NovoHttpConnectionUnavailableChunk, NovoToolErrorInfo, UsageAggregateRow, UsageEvent, UsageEventMeterKind, UsageEventResourceKind, UsageEventScope, UsageGroupBy, UsageNamespace, UsageTotal, UserInteractionAction, UserInteractionAnswer, UserInteractionOption, UserInteractionQuestion, UserInteractionRequestShape, UserInteractionResolution, WorkerStatus, WorkerStream, } from './types.js';
29
+ export { isNovoBrowserSession, isNovoCompaction, isNovoRunMeta, isNovoStepTerminal, isNovoTask, isNovoTerminal, isNovoToolApprovalResolved, isNovoTextDelta, isNovoToolApprovalRequested, isNovoToolCall, isNovoToolError, isNovoToolOutput, isNovoToolResultOverflow, isNovoToolServerUnavailable, isNovoHttpConnectionUnavailable, isNovoUsage, isNovoUserInteractionRequested, isNovoUserInteractionResolved, isNovoWorkerMeta, isNovoWorkerTerminal, isNovoWorkspace, readNovoToolError, } from './types.js';
29
30
  export { NovoAPIError, NovoAuthenticationError, NovoConfigurationError, NovoConflictError, NovoInsufficientQuotaError, NovoInvalidRequestError, NovoNotFoundError, NovoPermissionError, NovoRateLimitError, NovoServerError, NovoTimeoutError, } from './errors.js';
30
31
  export type { NovoErrorCode, NovoErrorType } from './errors.js';
31
32
  export { verifyNovoSignature } from './signature.js';
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  // private regardless of where it lives in the source tree. The
5
5
  // `packageSurface.test.ts` checks keep the published tarball honest.
6
6
  import { NovoConfigurationError } from './errors.js';
7
- import { NovoHttpClient, createAgentsNamespace, createArtifactsNamespace, createBrowserSessionsNamespace, createEnvironmentsNamespace, createEventSinksNamespace, createFilesNamespace, createGithubConnectionsNamespace, createInteractionsNamespace, createResultHandlersNamespace, createRunsNamespace, createSecretContextsNamespace, createSecretsNamespace, createThreadsNamespace, createToolApprovalHooksNamespace, createToolServersNamespace, createBandsNamespace, createUsageNamespace, } from './client.js';
7
+ import { NovoHttpClient, createAgentsNamespace, createArtifactsNamespace, createBrowserSessionsNamespace, createEnvironmentsNamespace, createEventSinksNamespace, createFilesNamespace, createGithubConnectionsNamespace, createInteractionsNamespace, createResultHandlersNamespace, createRunsNamespace, createSecretContextsNamespace, createSecretsNamespace, createThreadsNamespace, createToolApprovalHooksNamespace, createToolServersNamespace, createHttpConnectionsNamespace, createBandsNamespace, createUsageNamespace, } from './client.js';
8
8
  // ---------------------------------------------------------------------------
9
9
  // Client
10
10
  // ---------------------------------------------------------------------------
@@ -30,6 +30,7 @@ export class NovoAgents {
30
30
  secrets;
31
31
  secretContexts;
32
32
  toolServers;
33
+ httpConnections;
33
34
  usage;
34
35
  bands;
35
36
  client;
@@ -72,6 +73,7 @@ export class NovoAgents {
72
73
  this.secrets = createSecretsNamespace(this.client);
73
74
  this.secretContexts = createSecretContextsNamespace(this.client);
74
75
  this.toolServers = createToolServersNamespace(this.client);
76
+ this.httpConnections = createHttpConnectionsNamespace(this.client);
75
77
  this.usage = createUsageNamespace(this.client);
76
78
  this.bands = createBandsNamespace(this.client);
77
79
  }
@@ -80,7 +82,7 @@ function normalizeBaseUrl(baseUrl) {
80
82
  return baseUrl.replace(/\/+$/, '');
81
83
  }
82
84
  // Type guards
83
- export { isNovoBrowserSession, isNovoCompaction, isNovoRunMeta, isNovoStepTerminal, isNovoTask, isNovoTerminal, isNovoToolApprovalResolved, isNovoTextDelta, isNovoToolApprovalRequested, isNovoToolCall, isNovoToolError, isNovoToolOutput, isNovoToolResultOverflow, isNovoToolServerUnavailable, isNovoUsage, isNovoUserInteractionRequested, isNovoUserInteractionResolved, isNovoWorkerMeta, isNovoWorkerTerminal, isNovoWorkspace, readNovoToolError, } from './types.js';
85
+ export { isNovoBrowserSession, isNovoCompaction, isNovoRunMeta, isNovoStepTerminal, isNovoTask, isNovoTerminal, isNovoToolApprovalResolved, isNovoTextDelta, isNovoToolApprovalRequested, isNovoToolCall, isNovoToolError, isNovoToolOutput, isNovoToolResultOverflow, isNovoToolServerUnavailable, isNovoHttpConnectionUnavailable, isNovoUsage, isNovoUserInteractionRequested, isNovoUserInteractionResolved, isNovoWorkerMeta, isNovoWorkerTerminal, isNovoWorkspace, readNovoToolError, } from './types.js';
84
86
  // Errors
85
87
  export { NovoAPIError, NovoAuthenticationError, NovoConfigurationError, NovoConflictError, NovoInsufficientQuotaError, NovoInvalidRequestError, NovoNotFoundError, NovoPermissionError, NovoRateLimitError, NovoServerError, NovoTimeoutError, } from './errors.js';
86
88
  // Webhooks
package/dist/stream.d.ts CHANGED
@@ -32,6 +32,7 @@ export declare class NovoRunStream implements RunStream {
32
32
  private observedTerminalReason;
33
33
  private observedStatus;
34
34
  private observedUsage;
35
+ private observedOutput;
35
36
  private terminalSeen;
36
37
  private finalResultPromise;
37
38
  private activeReader;
package/dist/stream.js CHANGED
@@ -70,6 +70,10 @@ export class NovoRunStream {
70
70
  observedTerminalReason = null;
71
71
  observedStatus;
72
72
  observedUsage;
73
+ // Structured `output` captured from the `data-novo-terminal` chunk. Surfaced
74
+ // on `RunFinalResult.output`; stays `undefined` for runs without an
75
+ // `outputSchema`.
76
+ observedOutput;
73
77
  // Flips true once a `data-novo-terminal` chunk has been observed on this
74
78
  // stream. The SSE response is closed by the server at a fixed cap (~13 min
75
79
  // per connection) even when the run is still executing, so a clean EOF is
@@ -247,6 +251,7 @@ export class NovoRunStream {
247
251
  let usage;
248
252
  let status;
249
253
  let terminalReason = null;
254
+ let output;
250
255
  let lastId = this.lastSeenEventId;
251
256
  let reconnects = 0;
252
257
  for (;;) {
@@ -269,6 +274,8 @@ export class NovoRunStream {
269
274
  if (segment.observedStatus)
270
275
  status = segment.observedStatus;
271
276
  terminalReason = segment.observedTerminalReason ?? terminalReason;
277
+ if (segment.observedOutput !== undefined)
278
+ output = segment.observedOutput;
272
279
  lastId = segment.lastSeenEventId ?? lastId;
273
280
  if (segment.terminalSeen)
274
281
  break;
@@ -320,6 +327,7 @@ export class NovoRunStream {
320
327
  status: status ?? 'completed',
321
328
  terminalReason: terminalReason ?? null,
322
329
  usage: usage ?? EMPTY_USAGE,
330
+ ...(output !== undefined ? { output } : {}),
323
331
  };
324
332
  }
325
333
  pollRunOnce() {
@@ -433,6 +441,9 @@ export class NovoRunStream {
433
441
  if (event.data.terminalReason !== undefined) {
434
442
  this.observedTerminalReason = event.data.terminalReason;
435
443
  }
444
+ if (event.data.output !== undefined) {
445
+ this.observedOutput = event.data.output;
446
+ }
436
447
  return;
437
448
  }
438
449
  if (isNovoRunMeta(event)) {
@@ -464,6 +475,9 @@ export class NovoRunStream {
464
475
  status: run.status ?? this.observedStatus ?? 'completed',
465
476
  terminalReason: run.terminalReason ?? this.observedTerminalReason ?? null,
466
477
  usage,
478
+ ...(this.observedOutput !== undefined
479
+ ? { output: this.observedOutput }
480
+ : {}),
467
481
  };
468
482
  }
469
483
  async pollTerminalRun(runId) {
package/dist/types.d.ts CHANGED
@@ -233,6 +233,13 @@ export type NovoTerminalChunk = {
233
233
  error?: RunError;
234
234
  /** Novo-policy reason the run terminated; `null` if the run completed normally. */
235
235
  terminalReason: NovoTerminalReason | null;
236
+ /**
237
+ * Structured result for a run started with `outputSchema` — the value the
238
+ * model delivered via the `final_output` tool, shaped by that schema.
239
+ * Absent when no `outputSchema` was declared. Surfaced again on
240
+ * {@link RunFinalResult.output}.
241
+ */
242
+ output?: unknown;
236
243
  };
237
244
  };
238
245
  export type NovoTaskChunk = {
@@ -303,8 +310,8 @@ export type NovoWorkspaceChunk = {
303
310
  *
304
311
  * - `recovery: 'workspace'` — bytes spilled to a Novo-managed path in
305
312
  * the customer's attached workspace. `location.path`
306
- * is workspace-relative; the agent can `read_file` / `search_files`
307
- * / `find_files` against it via its existing tools.
313
+ * is workspace-relative; the agent can `read_file` / `grep`
314
+ * / `glob` against it via its existing tools.
308
315
  * - `recovery: 'remote-handler'` — bytes shipped to the customer's
309
316
  * `result_handler`. `location.url` (when present) is whatever the
310
317
  * handler returned; opaque to Novo. The agent itself cannot reach
@@ -413,6 +420,24 @@ export type NovoToolServerUnavailableChunk = {
413
420
  message: string;
414
421
  };
415
422
  };
423
+ export type NovoHttpConnectionUnavailableChunk = {
424
+ type: 'data-novo-http-connection-unavailable';
425
+ data: {
426
+ runId: string;
427
+ threadId: string;
428
+ agentId: string;
429
+ httpConnectionId?: string;
430
+ connectionName: string;
431
+ phase: 'connect' | 'load' | 'call';
432
+ toolName?: string;
433
+ toolCallId?: string;
434
+ errorCode: string;
435
+ status?: number;
436
+ attempts: number;
437
+ attemptsExhausted: boolean;
438
+ message: string;
439
+ };
440
+ };
416
441
  export type NovoToolApprovalRequestedChunk = {
417
442
  type: 'data-novo-tool-approval-requested';
418
443
  data: {
@@ -472,7 +497,7 @@ export type NovoUserInteractionResolvedChunk = {
472
497
  resolvedAt: string | null;
473
498
  };
474
499
  };
475
- export type NovoDataChunk = NovoRunMetaChunk | NovoUsageChunk | NovoStepTerminalChunk | NovoTerminalChunk | NovoTaskChunk | NovoWorkerMetaChunk | NovoWorkerTerminalChunk | NovoWorkspaceChunk | NovoToolCallChunk | NovoToolResultOverflowChunk | NovoCompactionChunk | NovoBrowserSessionChunk | NovoToolServerUnavailableChunk | NovoToolApprovalRequestedChunk | NovoToolApprovalResolvedChunk | NovoUserInteractionRequestedChunk | NovoUserInteractionResolvedChunk;
500
+ export type NovoDataChunk = NovoRunMetaChunk | NovoUsageChunk | NovoStepTerminalChunk | NovoTerminalChunk | NovoTaskChunk | NovoWorkerMetaChunk | NovoWorkerTerminalChunk | NovoWorkspaceChunk | NovoToolCallChunk | NovoToolResultOverflowChunk | NovoCompactionChunk | NovoBrowserSessionChunk | NovoToolServerUnavailableChunk | NovoHttpConnectionUnavailableChunk | NovoToolApprovalRequestedChunk | NovoToolApprovalResolvedChunk | NovoUserInteractionRequestedChunk | NovoUserInteractionResolvedChunk;
476
501
  export type NovoStreamChunk = {
477
502
  type: 'abort';
478
503
  reason?: string;
@@ -575,6 +600,7 @@ export declare function isNovoToolResultOverflow(event: NovoAgentEvent): event i
575
600
  export declare function isNovoToolCall(event: NovoAgentEvent): event is NovoToolCallChunk;
576
601
  export declare function isNovoBrowserSession(event: NovoAgentEvent): event is NovoBrowserSessionChunk;
577
602
  export declare function isNovoToolServerUnavailable(event: NovoAgentEvent): event is NovoToolServerUnavailableChunk;
603
+ export declare function isNovoHttpConnectionUnavailable(event: NovoAgentEvent): event is NovoHttpConnectionUnavailableChunk;
578
604
  /**
579
605
  * Per-modality switches for managed media generation. Used as the object form
580
606
  * of {@link AgentCapabilities.media}; `media: true` is shorthand for enabling
@@ -594,7 +620,6 @@ export type MediaGenerationConfig = {
594
620
  };
595
621
  export type AgentCapabilities = {
596
622
  web?: boolean;
597
- planning?: boolean;
598
623
  /** Enable the durable `request_user` tool for text, choices, forms, and review actions. */
599
624
  userInteraction?: boolean;
600
625
  /**
@@ -605,10 +630,12 @@ export type AgentCapabilities = {
605
630
  * to you under the root run via `interactions`.
606
631
  *
607
632
  * A delegated subagent is always a subset of its parent. Advisors stay
608
- * read-only for critique. Novo may grant workspace, shell, browser, media, or
609
- * MCP authority to workers only when needed and only if the parent already has
610
- * it. GitHub workflow authority, user interaction, and further delegation are
611
- * never delegated to a worker or advisor.
633
+ * read-only for critique. Novo may grant workspace, shell, browser, media,
634
+ * MCP tool-server, or OpenAPI HTTP-connection authority to workers only when
635
+ * needed and only if the parent already has it; each MCP server and HTTP
636
+ * connection is named explicitly and defaults to none. GitHub workflow
637
+ * authority, user interaction, and further delegation are never delegated to a
638
+ * worker or advisor.
612
639
  */
613
640
  subagents?: boolean;
614
641
  /**
@@ -668,6 +695,15 @@ export type AgentCapabilities = {
668
695
  mcp?: {
669
696
  toolServerIds: string[];
670
697
  };
698
+ /**
699
+ * Wire registered OpenAPI HTTP connections into this agent's toolset. Each
700
+ * connection's operations become callable as `api__{connection}__*`. Register
701
+ * connections with `novo.httpConnections.register` first, then list their ids
702
+ * here.
703
+ */
704
+ http?: {
705
+ connectionIds: string[];
706
+ };
671
707
  /**
672
708
  * Inline Agent Skills — on-demand instruction bundles for a workflow, tool
673
709
  * family, or domain. The agent sees a compact listing (name + short
@@ -1312,6 +1348,46 @@ export type ToolServerTestResult = {
1312
1348
  namespacedName: string;
1313
1349
  }>;
1314
1350
  };
1351
+ /** An OpenAPI HTTP connection — operations exposed as `api__{connection}__*`. */
1352
+ export type HttpConnection = {
1353
+ id: string;
1354
+ object: 'http_connection';
1355
+ name: string;
1356
+ /** The OpenAPI/Swagger document: a URL to fetch (JSON only in v0) or inline JSON. */
1357
+ spec: string;
1358
+ /** Explicit base URL; `null` falls back to the document's `servers[]` / host. */
1359
+ baseUrl: string | null;
1360
+ auth: HttpConnectionAuth;
1361
+ /** Allow-list of operation names; absent = all operations exposed. */
1362
+ allowedOperations?: string[];
1363
+ resultCapBytes?: number;
1364
+ trusted: boolean;
1365
+ /**
1366
+ * Policy gate. `false` = the cloud emits
1367
+ * `data-novo-http-connection-unavailable` with `errorCode: 'policy_denied'`
1368
+ * at run start and never loads the spec. Disable without deleting the row.
1369
+ */
1370
+ enabled: boolean;
1371
+ /** Per-row outbound call timeout (ms). `null` = use the platform default. */
1372
+ requestTimeoutMs: number | null;
1373
+ metadata: Metadata;
1374
+ configVersion: number;
1375
+ createdAt: string;
1376
+ updatedAt: string;
1377
+ };
1378
+ export type HttpConnectionAuth = {
1379
+ type: 'bearer';
1380
+ secretId: string;
1381
+ };
1382
+ export type HttpConnectionTestResult = {
1383
+ connected: true;
1384
+ latencyMs: number;
1385
+ operationCount: number;
1386
+ tools: Array<{
1387
+ name: string;
1388
+ namespacedName: string;
1389
+ }>;
1390
+ };
1315
1391
  export type DeleteAgentResponse = {
1316
1392
  id: string;
1317
1393
  object: 'agent';
@@ -1338,6 +1414,14 @@ export type RunFinalResult = {
1338
1414
  /** Novo-policy reason the run terminated. Null for normal completions. */
1339
1415
  terminalReason: NovoTerminalReason | null;
1340
1416
  usage: UsageTotal;
1417
+ /**
1418
+ * Structured result for a run started with `outputSchema` — the value the
1419
+ * model delivered via the `final_output` tool. Captured from the terminal
1420
+ * stream chunk; `undefined` when no `outputSchema` was declared (or the run
1421
+ * ended without calling `final_output`). Stream-surfaced only for now — not
1422
+ * yet exposed on `GET /v1/runs/:id`.
1423
+ */
1424
+ output?: unknown;
1341
1425
  };
1342
1426
  export type RunStartInput = {
1343
1427
  threadId: string;
@@ -1356,6 +1440,14 @@ export type RunStartInput = {
1356
1440
  dataHandling?: DataHandling;
1357
1441
  /** IANA timezone for this run's model-visible temporal context. */
1358
1442
  timeZone?: string;
1443
+ /**
1444
+ * JSON Schema describing this run's structured result. When provided, the run
1445
+ * delivers its answer by calling a constrained `final_output` tool, and the
1446
+ * structured value is surfaced as `output` on the terminal stream and on
1447
+ * {@link RunFinalResult.output} (also returned by `streamToCompletion()`).
1448
+ * Stream-surfaced only for now — not yet a persisted `GET /v1/runs/:id` field.
1449
+ */
1450
+ outputSchema?: Record<string, unknown>;
1359
1451
  budgetCents?: number;
1360
1452
  maxSteps?: number;
1361
1453
  maxDurationMs?: number;
@@ -1742,6 +1834,48 @@ export type ToolServersNamespace = {
1742
1834
  }>;
1743
1835
  test(toolServerId: string): Promise<ToolServerTestResult>;
1744
1836
  };
1837
+ export type HttpConnectionsNamespace = {
1838
+ register(input: {
1839
+ /** Slug used in `api__{connection}__{op}` names. Use 1-56 letters, numbers, `_`, or `-`; `__` is reserved. */
1840
+ name: string;
1841
+ /** OpenAPI/Swagger document: a URL to fetch (JSON only in v0) or inline JSON. */
1842
+ spec: string;
1843
+ /** Explicit base URL; omit to use the document's `servers[]` / host. */
1844
+ baseUrl?: string;
1845
+ auth: HttpConnectionAuth;
1846
+ /** Allow-list of operation names; omit to expose all operations. */
1847
+ allowedOperations?: string[];
1848
+ resultCapBytes?: number;
1849
+ trusted?: boolean;
1850
+ /** Defaults to `true` server-side. Set `false` to register a connection
1851
+ * that's denied at run start until flipped on. */
1852
+ enabled?: boolean;
1853
+ requestTimeoutMs?: number | null;
1854
+ metadata?: Metadata;
1855
+ }): Promise<HttpConnection>;
1856
+ list(): Promise<Page<HttpConnection>>;
1857
+ get(httpConnectionId: string): Promise<HttpConnection>;
1858
+ /** Partial update. `enabled` flips the policy gate; `trusted` flips the trust
1859
+ * boundary; `auth` may switch to a different reusable secret. */
1860
+ update(httpConnectionId: string, input: {
1861
+ name?: string;
1862
+ spec?: string;
1863
+ baseUrl?: string;
1864
+ auth?: HttpConnectionAuth;
1865
+ allowedOperations?: string[];
1866
+ resultCapBytes?: number;
1867
+ trusted?: boolean;
1868
+ enabled?: boolean;
1869
+ requestTimeoutMs?: number | null;
1870
+ metadata?: MetadataPatch;
1871
+ }): Promise<HttpConnection>;
1872
+ delete(httpConnectionId: string): Promise<{
1873
+ id: string;
1874
+ object: 'http_connection';
1875
+ deleted: true;
1876
+ }>;
1877
+ test(httpConnectionId: string): Promise<HttpConnectionTestResult>;
1878
+ };
1745
1879
  /**
1746
1880
  * Aggregated customer-facing usage data, accessible via `novo.usage.aggregate()`.
1747
1881
  *
@@ -1908,6 +2042,12 @@ export type ThreadsNamespace = {
1908
2042
  dataHandling?: DataHandling;
1909
2043
  /** IANA timezone for this run's model-visible temporal context. */
1910
2044
  timeZone?: string;
2045
+ /**
2046
+ * JSON Schema for this run's structured result — see
2047
+ * {@link RunStartInput.outputSchema}. Surfaced as `output` on the terminal
2048
+ * stream and {@link RunFinalResult.output}.
2049
+ */
2050
+ outputSchema?: Record<string, unknown>;
1911
2051
  budgetCents?: number;
1912
2052
  maxSteps?: number;
1913
2053
  maxDurationMs?: number;
package/dist/types.js CHANGED
@@ -132,6 +132,10 @@ export function isNovoBrowserSession(event) {
132
132
  export function isNovoToolServerUnavailable(event) {
133
133
  return (event.type === 'data-novo-tool-server-unavailable' && hasObjectData(event));
134
134
  }
135
+ export function isNovoHttpConnectionUnavailable(event) {
136
+ return (event.type === 'data-novo-http-connection-unavailable' &&
137
+ hasObjectData(event));
138
+ }
135
139
  function isDelegationRole(value) {
136
140
  return value === 'worker' || value === 'advisor';
137
141
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "novoagents",
3
- "version": "0.3.0-alpha.21",
3
+ "version": "0.3.0-alpha.23",
4
4
  "description": "Thin TypeScript SDK for the Novo Agents hosted API.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",