novoagents 0.3.0-alpha.21 → 0.3.0-alpha.22

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,20 @@ Internal engine, routing, and infrastructure changes are intentionally omitted.
5
5
 
6
6
  ## Unreleased
7
7
 
8
+ ## 0.3.0-alpha.22 - 2026-06-18
9
+
10
+ - Added HTTP connections for registering OpenAPI-backed tools through
11
+ `novo.httpConnections` and attaching them with
12
+ `capabilities.http.connectionIds`.
13
+ - Runs can now declare `outputSchema`; structured final values surface on
14
+ `data-novo-terminal.output` and `RunFinalResult.output`.
15
+ - Disabled, missing, or policy-denied HTTP connections now emit
16
+ `data-novo-http-connection-unavailable` and use stable
17
+ `http_connection_not_found` / `policy_denied` errors.
18
+ - Public shell tool names are now canonicalized to `bash` across stream chunks,
19
+ approval hooks, event sinks, and run resources. The capability key remains
20
+ `terminal.run`; customer policy should branch on public `toolName: 'bash'`.
21
+
8
22
  ## 0.3.0-alpha.21 - 2026-06-18
9
23
 
10
24
  - 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
@@ -605,10 +631,12 @@ export type AgentCapabilities = {
605
631
  * to you under the root run via `interactions`.
606
632
  *
607
633
  * 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.
634
+ * read-only for critique. Novo may grant workspace, shell, browser, media,
635
+ * MCP tool-server, or OpenAPI HTTP-connection authority to workers only when
636
+ * needed and only if the parent already has it; each MCP server and HTTP
637
+ * connection is named explicitly and defaults to none. GitHub workflow
638
+ * authority, user interaction, and further delegation are never delegated to a
639
+ * worker or advisor.
612
640
  */
613
641
  subagents?: boolean;
614
642
  /**
@@ -668,6 +696,15 @@ export type AgentCapabilities = {
668
696
  mcp?: {
669
697
  toolServerIds: string[];
670
698
  };
699
+ /**
700
+ * Wire registered OpenAPI HTTP connections into this agent's toolset. Each
701
+ * connection's operations become callable as `api__{connection}__*`. Register
702
+ * connections with `novo.httpConnections.register` first, then list their ids
703
+ * here.
704
+ */
705
+ http?: {
706
+ connectionIds: string[];
707
+ };
671
708
  /**
672
709
  * Inline Agent Skills — on-demand instruction bundles for a workflow, tool
673
710
  * family, or domain. The agent sees a compact listing (name + short
@@ -1312,6 +1349,46 @@ export type ToolServerTestResult = {
1312
1349
  namespacedName: string;
1313
1350
  }>;
1314
1351
  };
1352
+ /** An OpenAPI HTTP connection — operations exposed as `api__{connection}__*`. */
1353
+ export type HttpConnection = {
1354
+ id: string;
1355
+ object: 'http_connection';
1356
+ name: string;
1357
+ /** The OpenAPI/Swagger document: a URL to fetch (JSON only in v0) or inline JSON. */
1358
+ spec: string;
1359
+ /** Explicit base URL; `null` falls back to the document's `servers[]` / host. */
1360
+ baseUrl: string | null;
1361
+ auth: HttpConnectionAuth;
1362
+ /** Allow-list of operation names; absent = all operations exposed. */
1363
+ allowedOperations?: string[];
1364
+ resultCapBytes?: number;
1365
+ trusted: boolean;
1366
+ /**
1367
+ * Policy gate. `false` = the cloud emits
1368
+ * `data-novo-http-connection-unavailable` with `errorCode: 'policy_denied'`
1369
+ * at run start and never loads the spec. Disable without deleting the row.
1370
+ */
1371
+ enabled: boolean;
1372
+ /** Per-row outbound call timeout (ms). `null` = use the platform default. */
1373
+ requestTimeoutMs: number | null;
1374
+ metadata: Metadata;
1375
+ configVersion: number;
1376
+ createdAt: string;
1377
+ updatedAt: string;
1378
+ };
1379
+ export type HttpConnectionAuth = {
1380
+ type: 'bearer';
1381
+ secretId: string;
1382
+ };
1383
+ export type HttpConnectionTestResult = {
1384
+ connected: true;
1385
+ latencyMs: number;
1386
+ operationCount: number;
1387
+ tools: Array<{
1388
+ name: string;
1389
+ namespacedName: string;
1390
+ }>;
1391
+ };
1315
1392
  export type DeleteAgentResponse = {
1316
1393
  id: string;
1317
1394
  object: 'agent';
@@ -1338,6 +1415,14 @@ export type RunFinalResult = {
1338
1415
  /** Novo-policy reason the run terminated. Null for normal completions. */
1339
1416
  terminalReason: NovoTerminalReason | null;
1340
1417
  usage: UsageTotal;
1418
+ /**
1419
+ * Structured result for a run started with `outputSchema` — the value the
1420
+ * model delivered via the `final_output` tool. Captured from the terminal
1421
+ * stream chunk; `undefined` when no `outputSchema` was declared (or the run
1422
+ * ended without calling `final_output`). Stream-surfaced only for now — not
1423
+ * yet exposed on `GET /v1/runs/:id`.
1424
+ */
1425
+ output?: unknown;
1341
1426
  };
1342
1427
  export type RunStartInput = {
1343
1428
  threadId: string;
@@ -1356,6 +1441,14 @@ export type RunStartInput = {
1356
1441
  dataHandling?: DataHandling;
1357
1442
  /** IANA timezone for this run's model-visible temporal context. */
1358
1443
  timeZone?: string;
1444
+ /**
1445
+ * JSON Schema describing this run's structured result. When provided, the run
1446
+ * delivers its answer by calling a constrained `final_output` tool, and the
1447
+ * structured value is surfaced as `output` on the terminal stream and on
1448
+ * {@link RunFinalResult.output} (also returned by `streamToCompletion()`).
1449
+ * Stream-surfaced only for now — not yet a persisted `GET /v1/runs/:id` field.
1450
+ */
1451
+ outputSchema?: Record<string, unknown>;
1359
1452
  budgetCents?: number;
1360
1453
  maxSteps?: number;
1361
1454
  maxDurationMs?: number;
@@ -1742,6 +1835,48 @@ export type ToolServersNamespace = {
1742
1835
  }>;
1743
1836
  test(toolServerId: string): Promise<ToolServerTestResult>;
1744
1837
  };
1838
+ export type HttpConnectionsNamespace = {
1839
+ register(input: {
1840
+ /** Slug used in `api__{connection}__{op}` names. Use 1-56 letters, numbers, `_`, or `-`; `__` is reserved. */
1841
+ name: string;
1842
+ /** OpenAPI/Swagger document: a URL to fetch (JSON only in v0) or inline JSON. */
1843
+ spec: string;
1844
+ /** Explicit base URL; omit to use the document's `servers[]` / host. */
1845
+ baseUrl?: string;
1846
+ auth: HttpConnectionAuth;
1847
+ /** Allow-list of operation names; omit to expose all operations. */
1848
+ allowedOperations?: string[];
1849
+ resultCapBytes?: number;
1850
+ trusted?: boolean;
1851
+ /** Defaults to `true` server-side. Set `false` to register a connection
1852
+ * that's denied at run start until flipped on. */
1853
+ enabled?: boolean;
1854
+ requestTimeoutMs?: number | null;
1855
+ metadata?: Metadata;
1856
+ }): Promise<HttpConnection>;
1857
+ list(): Promise<Page<HttpConnection>>;
1858
+ get(httpConnectionId: string): Promise<HttpConnection>;
1859
+ /** Partial update. `enabled` flips the policy gate; `trusted` flips the trust
1860
+ * boundary; `auth` may switch to a different reusable secret. */
1861
+ update(httpConnectionId: string, input: {
1862
+ name?: string;
1863
+ spec?: string;
1864
+ baseUrl?: string;
1865
+ auth?: HttpConnectionAuth;
1866
+ allowedOperations?: string[];
1867
+ resultCapBytes?: number;
1868
+ trusted?: boolean;
1869
+ enabled?: boolean;
1870
+ requestTimeoutMs?: number | null;
1871
+ metadata?: MetadataPatch;
1872
+ }): Promise<HttpConnection>;
1873
+ delete(httpConnectionId: string): Promise<{
1874
+ id: string;
1875
+ object: 'http_connection';
1876
+ deleted: true;
1877
+ }>;
1878
+ test(httpConnectionId: string): Promise<HttpConnectionTestResult>;
1879
+ };
1745
1880
  /**
1746
1881
  * Aggregated customer-facing usage data, accessible via `novo.usage.aggregate()`.
1747
1882
  *
@@ -1908,6 +2043,12 @@ export type ThreadsNamespace = {
1908
2043
  dataHandling?: DataHandling;
1909
2044
  /** IANA timezone for this run's model-visible temporal context. */
1910
2045
  timeZone?: string;
2046
+ /**
2047
+ * JSON Schema for this run's structured result — see
2048
+ * {@link RunStartInput.outputSchema}. Surfaced as `output` on the terminal
2049
+ * stream and {@link RunFinalResult.output}.
2050
+ */
2051
+ outputSchema?: Record<string, unknown>;
1911
2052
  budgetCents?: number;
1912
2053
  maxSteps?: number;
1913
2054
  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.22",
4
4
  "description": "Thin TypeScript SDK for the Novo Agents hosted API.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",