wauldo 0.7.2 → 0.9.0

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/README.md CHANGED
@@ -116,6 +116,39 @@ console.log(result.action); // "block"
116
116
  console.log(result.claims[0].reason); // "numerical_mismatch"
117
117
  ```
118
118
 
119
+ ### Deployed Agents — create, run, stream
120
+
121
+ ```typescript
122
+ import { AgentsClient } from 'wauldo';
123
+
124
+ const agents = new AgentsClient({
125
+ baseUrl: 'https://api.wauldo.com',
126
+ apiKey: 'YOUR_API_KEY',
127
+ tenant: 'my-tenant',
128
+ });
129
+
130
+ const agent = await agents.create({
131
+ name: 'support-bot',
132
+ description: 'Answers refund questions',
133
+ wauldoToml: `[agent]\nname = "support-bot"\n[model]\nprovider = "openrouter"\nname = "auto"`,
134
+ preset: 'general_task', // or 'rust_backend_architect', 'rag_data_engineer', ...
135
+ });
136
+
137
+ const run = await agents.run(agent.id, 'Can I return a shirt 30 days after purchase?');
138
+
139
+ // Stream reasoning live as each workflow state completes
140
+ for await (const event of agents.streamTask(run.task_id)) {
141
+ console.log(` ${event.state_name}: ${event.duration_ms}ms (${event.completion_tokens} tok)`);
142
+ }
143
+
144
+ // Or poll for the final verified result
145
+ const task = await agents.waitForTask(run.task_id, { timeoutMs: 120_000 });
146
+ console.log(task.result); // The answer
147
+ console.log(task.verification?.verdict); // SAFE | UNVERIFIED | BLOCK | …
148
+ console.log(task.verification?.trust_score); // 0.0 – 1.0
149
+ console.log(task.verification?.message); // Human-readable context when non-SAFE
150
+ ```
151
+
119
152
  ### Chat (OpenAI-compatible)
120
153
 
121
154
  ```typescript
package/dist/index.d.mts CHANGED
@@ -644,4 +644,175 @@ declare class ToolNotFoundError extends WauldoError {
644
644
  constructor(toolName: string);
645
645
  }
646
646
 
647
- export { AgentClient, type CallToolResponse, type ChatChoice, type ChatClientLike, type ChatMessage, type ChatRequest, type ChatResponse, type ChatUsage, type Chunk, type ChunkResult, type ClientOptions, type Concept, type ConceptResult, ConnectionError, Conversation, type DetailLevel, type EmbeddingData, type EmbeddingResponse, type EmbeddingUsage, type GraphNode, type GuardClaim, type GuardMode, type GuardResponse, HttpClient, type HttpClientConfig, type KnowledgeGraphResult, type LogLevel, MockHttpClient, type ModelInfo, type ModelList, type OrchestratorResponse, type PlanOptions, type PlanResult, type PlanStep, type RagAuditInfo, type RagQueryResponse, type RagSource, type RagUploadResponse, type ReasoningOptions, type ReasoningResult, type RequestOptions, type RetrievalResult, ServerError, type SourceType, TimeoutError, type ToolContent, type ToolDefinition, ToolNotFoundError, ValidationError, WauldoError, chatContent, guardIsBlocked, guardIsSafe };
647
+ interface AgentsClientConfig {
648
+ baseUrl: string;
649
+ apiKey?: string;
650
+ /** Tenant identifier forwarded via x-rapidapi-user header. */
651
+ tenant?: string;
652
+ /** Per-request timeout in ms. Default 120_000. */
653
+ timeoutMs?: number;
654
+ }
655
+ interface DeployedAgent {
656
+ id: string;
657
+ tenant_id: string;
658
+ name: string;
659
+ description: string;
660
+ wauldo_toml: string;
661
+ agents_md?: string;
662
+ mcp_json?: string;
663
+ model_provider: string;
664
+ model_name: string;
665
+ preset?: string;
666
+ created_at: number;
667
+ updated_at: number;
668
+ }
669
+ interface CreateAgentInput {
670
+ name: string;
671
+ wauldoToml: string;
672
+ description?: string;
673
+ agentsMd?: string;
674
+ mcpJson?: string;
675
+ preset?: string;
676
+ }
677
+ interface UpdateAgentPatch {
678
+ description?: string;
679
+ wauldoToml?: string;
680
+ agentsMd?: string;
681
+ mcpJson?: string;
682
+ preset?: string;
683
+ }
684
+ interface AgentListResponse {
685
+ agents: DeployedAgent[];
686
+ pagination: {
687
+ total: number;
688
+ limit: number;
689
+ offset: number;
690
+ };
691
+ }
692
+ interface AgentRunResponse {
693
+ task_id: string;
694
+ agent_id: string;
695
+ status: string;
696
+ created_at: number;
697
+ }
698
+ interface A2aResponse {
699
+ task_id: string;
700
+ agent_id: string;
701
+ trace: string[];
702
+ depth: number;
703
+ status: string;
704
+ }
705
+ /** Verification verdict returned on completed tasks. */
706
+ type Verdict = "SAFE" | "UNCERTAIN" | "PARTIAL" | "BLOCK" | "CONFLICT" | "UNVERIFIED";
707
+ /** Task lifecycle status. */
708
+ type TaskStatus = "queued" | "running" | "completed" | "failed" | "cancelled";
709
+ /** A single verified claim from an agent output. */
710
+ interface TaskClaim {
711
+ text: string;
712
+ supported: boolean;
713
+ confidence: number;
714
+ }
715
+ /**
716
+ * Verification block attached to completed tasks. When
717
+ * `verification_source === "prompt_only"` the `confidence` and
718
+ * `hallucination_rate` fields reflect self-consistency only; rely on
719
+ * `verdict` + `trust_score` + `message` as authoritative.
720
+ */
721
+ interface TaskVerification {
722
+ verdict: Verdict;
723
+ hallucination_rate: number;
724
+ confidence: number;
725
+ trust_score: number;
726
+ verification_source: string;
727
+ claims: TaskClaim[];
728
+ verification_retries: number;
729
+ /** Human-readable context for non-SAFE verdicts. */
730
+ message?: string | null;
731
+ sources_cited?: number[];
732
+ stripped_claims?: string[];
733
+ }
734
+ /** Full task record returned by `GET /v1/tasks/:id`. */
735
+ interface Task {
736
+ task_id: string;
737
+ tenant_id: string;
738
+ status: TaskStatus;
739
+ prompt: string;
740
+ created_at: number;
741
+ updated_at: number;
742
+ preset?: string | null;
743
+ result?: string | null;
744
+ error?: string | null;
745
+ partial_result?: string | null;
746
+ verification?: TaskVerification | null;
747
+ journal?: Record<string, unknown> | null;
748
+ }
749
+ /**
750
+ * Single event yielded by `GET /v1/tasks/:id/stream`. Each SSE `data:`
751
+ * line is a JSON-serialised StateTransition emitted when a workflow
752
+ * state completes.
753
+ */
754
+ interface StateTransition {
755
+ state_name: string;
756
+ to_state?: string | null;
757
+ condition: string;
758
+ raw_output: string;
759
+ validation_notes: string[];
760
+ timestamp: number;
761
+ success: boolean;
762
+ retry_count: number;
763
+ duration_ms: number;
764
+ prompt_tokens: number;
765
+ completion_tokens: number;
766
+ repair_count: number;
767
+ cache_hit: boolean;
768
+ }
769
+ declare function isTerminalStatus(s: TaskStatus | string): boolean;
770
+ declare class HttpError extends Error {
771
+ status: number;
772
+ statusText: string;
773
+ body: string;
774
+ constructor(status: number, statusText: string, body: string);
775
+ }
776
+ declare class AgentsClient {
777
+ private readonly config;
778
+ constructor(config: AgentsClientConfig);
779
+ private headers;
780
+ private request;
781
+ create(input: CreateAgentInput): Promise<DeployedAgent>;
782
+ list(limit?: number, offset?: number): Promise<AgentListResponse>;
783
+ get(agentId: string): Promise<DeployedAgent>;
784
+ update(agentId: string, patch: UpdateAgentPatch): Promise<DeployedAgent>;
785
+ delete(agentId: string): Promise<void>;
786
+ run(agentId: string, input: string, verificationMode?: "strict" | "balanced" | "permissive", factCheckMode?: "lexical" | "hybrid" | "semantic"): Promise<AgentRunResponse>;
787
+ a2aInvoke(agentId: string, input: string, trace?: string[], verificationMode?: "strict" | "balanced" | "permissive", factCheckMode?: "lexical" | "hybrid" | "semantic"): Promise<A2aResponse>;
788
+ /** `GET /v1/tasks/:id` — fetch the current state of a task. */
789
+ getTask(taskId: string): Promise<Task>;
790
+ /** `DELETE /v1/tasks/:id` — cancel a queued or running task. */
791
+ cancelTask(taskId: string): Promise<void>;
792
+ /**
793
+ * Poll `getTask` until the task reaches a terminal status. Resolves
794
+ * with the final Task snapshot. Rejects with `Error("timeout")` if
795
+ * the task is still running after `timeoutMs`. Use `streamTask` when
796
+ * you need event-by-event progress instead of a single final state.
797
+ */
798
+ waitForTask(taskId: string, opts?: {
799
+ timeoutMs?: number;
800
+ pollIntervalMs?: number;
801
+ }): Promise<Task>;
802
+ /**
803
+ * Subscribe to `GET /v1/tasks/:id/stream` and yield typed
804
+ * StateTransition events as each workflow state completes. The
805
+ * generator closes when the upstream stream closes (task reached
806
+ * terminal status) or on connection error.
807
+ *
808
+ * @example
809
+ * ```ts
810
+ * for await (const event of agents.streamTask(run.task_id)) {
811
+ * console.log(event.state_name, event.duration_ms);
812
+ * }
813
+ * ```
814
+ */
815
+ streamTask(taskId: string): AsyncGenerator<StateTransition>;
816
+ }
817
+
818
+ export { type A2aResponse, AgentClient, type AgentListResponse, type AgentRunResponse, AgentsClient, type AgentsClientConfig, type CallToolResponse, type ChatChoice, type ChatClientLike, type ChatMessage, type ChatRequest, type ChatResponse, type ChatUsage, type Chunk, type ChunkResult, type ClientOptions, type Concept, type ConceptResult, ConnectionError, Conversation, type CreateAgentInput, type DeployedAgent, type DetailLevel, type EmbeddingData, type EmbeddingResponse, type EmbeddingUsage, type GraphNode, type GuardClaim, type GuardMode, type GuardResponse, HttpClient, type HttpClientConfig, HttpError, type KnowledgeGraphResult, type LogLevel, MockHttpClient, type ModelInfo, type ModelList, type OrchestratorResponse, type PlanOptions, type PlanResult, type PlanStep, type RagAuditInfo, type RagQueryResponse, type RagSource, type RagUploadResponse, type ReasoningOptions, type ReasoningResult, type RequestOptions, type RetrievalResult, ServerError, type SourceType, type StateTransition, type Task, type TaskClaim, type TaskStatus, type TaskVerification, TimeoutError, type ToolContent, type ToolDefinition, ToolNotFoundError, type UpdateAgentPatch, ValidationError, type Verdict, WauldoError, chatContent, guardIsBlocked, guardIsSafe, isTerminalStatus };
package/dist/index.d.ts CHANGED
@@ -644,4 +644,175 @@ declare class ToolNotFoundError extends WauldoError {
644
644
  constructor(toolName: string);
645
645
  }
646
646
 
647
- export { AgentClient, type CallToolResponse, type ChatChoice, type ChatClientLike, type ChatMessage, type ChatRequest, type ChatResponse, type ChatUsage, type Chunk, type ChunkResult, type ClientOptions, type Concept, type ConceptResult, ConnectionError, Conversation, type DetailLevel, type EmbeddingData, type EmbeddingResponse, type EmbeddingUsage, type GraphNode, type GuardClaim, type GuardMode, type GuardResponse, HttpClient, type HttpClientConfig, type KnowledgeGraphResult, type LogLevel, MockHttpClient, type ModelInfo, type ModelList, type OrchestratorResponse, type PlanOptions, type PlanResult, type PlanStep, type RagAuditInfo, type RagQueryResponse, type RagSource, type RagUploadResponse, type ReasoningOptions, type ReasoningResult, type RequestOptions, type RetrievalResult, ServerError, type SourceType, TimeoutError, type ToolContent, type ToolDefinition, ToolNotFoundError, ValidationError, WauldoError, chatContent, guardIsBlocked, guardIsSafe };
647
+ interface AgentsClientConfig {
648
+ baseUrl: string;
649
+ apiKey?: string;
650
+ /** Tenant identifier forwarded via x-rapidapi-user header. */
651
+ tenant?: string;
652
+ /** Per-request timeout in ms. Default 120_000. */
653
+ timeoutMs?: number;
654
+ }
655
+ interface DeployedAgent {
656
+ id: string;
657
+ tenant_id: string;
658
+ name: string;
659
+ description: string;
660
+ wauldo_toml: string;
661
+ agents_md?: string;
662
+ mcp_json?: string;
663
+ model_provider: string;
664
+ model_name: string;
665
+ preset?: string;
666
+ created_at: number;
667
+ updated_at: number;
668
+ }
669
+ interface CreateAgentInput {
670
+ name: string;
671
+ wauldoToml: string;
672
+ description?: string;
673
+ agentsMd?: string;
674
+ mcpJson?: string;
675
+ preset?: string;
676
+ }
677
+ interface UpdateAgentPatch {
678
+ description?: string;
679
+ wauldoToml?: string;
680
+ agentsMd?: string;
681
+ mcpJson?: string;
682
+ preset?: string;
683
+ }
684
+ interface AgentListResponse {
685
+ agents: DeployedAgent[];
686
+ pagination: {
687
+ total: number;
688
+ limit: number;
689
+ offset: number;
690
+ };
691
+ }
692
+ interface AgentRunResponse {
693
+ task_id: string;
694
+ agent_id: string;
695
+ status: string;
696
+ created_at: number;
697
+ }
698
+ interface A2aResponse {
699
+ task_id: string;
700
+ agent_id: string;
701
+ trace: string[];
702
+ depth: number;
703
+ status: string;
704
+ }
705
+ /** Verification verdict returned on completed tasks. */
706
+ type Verdict = "SAFE" | "UNCERTAIN" | "PARTIAL" | "BLOCK" | "CONFLICT" | "UNVERIFIED";
707
+ /** Task lifecycle status. */
708
+ type TaskStatus = "queued" | "running" | "completed" | "failed" | "cancelled";
709
+ /** A single verified claim from an agent output. */
710
+ interface TaskClaim {
711
+ text: string;
712
+ supported: boolean;
713
+ confidence: number;
714
+ }
715
+ /**
716
+ * Verification block attached to completed tasks. When
717
+ * `verification_source === "prompt_only"` the `confidence` and
718
+ * `hallucination_rate` fields reflect self-consistency only; rely on
719
+ * `verdict` + `trust_score` + `message` as authoritative.
720
+ */
721
+ interface TaskVerification {
722
+ verdict: Verdict;
723
+ hallucination_rate: number;
724
+ confidence: number;
725
+ trust_score: number;
726
+ verification_source: string;
727
+ claims: TaskClaim[];
728
+ verification_retries: number;
729
+ /** Human-readable context for non-SAFE verdicts. */
730
+ message?: string | null;
731
+ sources_cited?: number[];
732
+ stripped_claims?: string[];
733
+ }
734
+ /** Full task record returned by `GET /v1/tasks/:id`. */
735
+ interface Task {
736
+ task_id: string;
737
+ tenant_id: string;
738
+ status: TaskStatus;
739
+ prompt: string;
740
+ created_at: number;
741
+ updated_at: number;
742
+ preset?: string | null;
743
+ result?: string | null;
744
+ error?: string | null;
745
+ partial_result?: string | null;
746
+ verification?: TaskVerification | null;
747
+ journal?: Record<string, unknown> | null;
748
+ }
749
+ /**
750
+ * Single event yielded by `GET /v1/tasks/:id/stream`. Each SSE `data:`
751
+ * line is a JSON-serialised StateTransition emitted when a workflow
752
+ * state completes.
753
+ */
754
+ interface StateTransition {
755
+ state_name: string;
756
+ to_state?: string | null;
757
+ condition: string;
758
+ raw_output: string;
759
+ validation_notes: string[];
760
+ timestamp: number;
761
+ success: boolean;
762
+ retry_count: number;
763
+ duration_ms: number;
764
+ prompt_tokens: number;
765
+ completion_tokens: number;
766
+ repair_count: number;
767
+ cache_hit: boolean;
768
+ }
769
+ declare function isTerminalStatus(s: TaskStatus | string): boolean;
770
+ declare class HttpError extends Error {
771
+ status: number;
772
+ statusText: string;
773
+ body: string;
774
+ constructor(status: number, statusText: string, body: string);
775
+ }
776
+ declare class AgentsClient {
777
+ private readonly config;
778
+ constructor(config: AgentsClientConfig);
779
+ private headers;
780
+ private request;
781
+ create(input: CreateAgentInput): Promise<DeployedAgent>;
782
+ list(limit?: number, offset?: number): Promise<AgentListResponse>;
783
+ get(agentId: string): Promise<DeployedAgent>;
784
+ update(agentId: string, patch: UpdateAgentPatch): Promise<DeployedAgent>;
785
+ delete(agentId: string): Promise<void>;
786
+ run(agentId: string, input: string, verificationMode?: "strict" | "balanced" | "permissive", factCheckMode?: "lexical" | "hybrid" | "semantic"): Promise<AgentRunResponse>;
787
+ a2aInvoke(agentId: string, input: string, trace?: string[], verificationMode?: "strict" | "balanced" | "permissive", factCheckMode?: "lexical" | "hybrid" | "semantic"): Promise<A2aResponse>;
788
+ /** `GET /v1/tasks/:id` — fetch the current state of a task. */
789
+ getTask(taskId: string): Promise<Task>;
790
+ /** `DELETE /v1/tasks/:id` — cancel a queued or running task. */
791
+ cancelTask(taskId: string): Promise<void>;
792
+ /**
793
+ * Poll `getTask` until the task reaches a terminal status. Resolves
794
+ * with the final Task snapshot. Rejects with `Error("timeout")` if
795
+ * the task is still running after `timeoutMs`. Use `streamTask` when
796
+ * you need event-by-event progress instead of a single final state.
797
+ */
798
+ waitForTask(taskId: string, opts?: {
799
+ timeoutMs?: number;
800
+ pollIntervalMs?: number;
801
+ }): Promise<Task>;
802
+ /**
803
+ * Subscribe to `GET /v1/tasks/:id/stream` and yield typed
804
+ * StateTransition events as each workflow state completes. The
805
+ * generator closes when the upstream stream closes (task reached
806
+ * terminal status) or on connection error.
807
+ *
808
+ * @example
809
+ * ```ts
810
+ * for await (const event of agents.streamTask(run.task_id)) {
811
+ * console.log(event.state_name, event.duration_ms);
812
+ * }
813
+ * ```
814
+ */
815
+ streamTask(taskId: string): AsyncGenerator<StateTransition>;
816
+ }
817
+
818
+ export { type A2aResponse, AgentClient, type AgentListResponse, type AgentRunResponse, AgentsClient, type AgentsClientConfig, type CallToolResponse, type ChatChoice, type ChatClientLike, type ChatMessage, type ChatRequest, type ChatResponse, type ChatUsage, type Chunk, type ChunkResult, type ClientOptions, type Concept, type ConceptResult, ConnectionError, Conversation, type CreateAgentInput, type DeployedAgent, type DetailLevel, type EmbeddingData, type EmbeddingResponse, type EmbeddingUsage, type GraphNode, type GuardClaim, type GuardMode, type GuardResponse, HttpClient, type HttpClientConfig, HttpError, type KnowledgeGraphResult, type LogLevel, MockHttpClient, type ModelInfo, type ModelList, type OrchestratorResponse, type PlanOptions, type PlanResult, type PlanStep, type RagAuditInfo, type RagQueryResponse, type RagSource, type RagUploadResponse, type ReasoningOptions, type ReasoningResult, type RequestOptions, type RetrievalResult, ServerError, type SourceType, type StateTransition, type Task, type TaskClaim, type TaskStatus, type TaskVerification, TimeoutError, type ToolContent, type ToolDefinition, ToolNotFoundError, type UpdateAgentPatch, ValidationError, type Verdict, WauldoError, chatContent, guardIsBlocked, guardIsSafe, isTerminalStatus };
package/dist/index.js CHANGED
@@ -21,9 +21,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AgentClient: () => AgentClient,
24
+ AgentsClient: () => AgentsClient,
24
25
  ConnectionError: () => ConnectionError,
25
26
  Conversation: () => Conversation,
26
27
  HttpClient: () => HttpClient,
28
+ HttpError: () => HttpError,
27
29
  MockHttpClient: () => MockHttpClient,
28
30
  ServerError: () => ServerError,
29
31
  TimeoutError: () => TimeoutError,
@@ -32,7 +34,8 @@ __export(index_exports, {
32
34
  WauldoError: () => WauldoError,
33
35
  chatContent: () => chatContent,
34
36
  guardIsBlocked: () => guardIsBlocked,
35
- guardIsSafe: () => guardIsSafe
37
+ guardIsSafe: () => guardIsSafe,
38
+ isTerminalStatus: () => isTerminalStatus
36
39
  });
37
40
  module.exports = __toCommonJS(index_exports);
38
41
 
@@ -1284,12 +1287,241 @@ function guardIsSafe(response) {
1284
1287
  function guardIsBlocked(response) {
1285
1288
  return response.action === "block";
1286
1289
  }
1290
+
1291
+ // src/agents.ts
1292
+ var MAX_RESPONSE_SIZE = 10 * 1024 * 1024;
1293
+ function isTerminalStatus(s) {
1294
+ return s === "completed" || s === "failed" || s === "cancelled";
1295
+ }
1296
+ async function _boundedRead(resp, limit = MAX_RESPONSE_SIZE) {
1297
+ if (!resp.body) return new Uint8Array(0);
1298
+ const reader = resp.body.getReader();
1299
+ const chunks = [];
1300
+ let total = 0;
1301
+ while (true) {
1302
+ const { done, value } = await reader.read();
1303
+ if (done) break;
1304
+ if (value) {
1305
+ total += value.byteLength;
1306
+ if (total > limit) {
1307
+ try {
1308
+ await reader.cancel();
1309
+ } catch {
1310
+ }
1311
+ throw new Error(
1312
+ `response body too large: >${limit} bytes`
1313
+ );
1314
+ }
1315
+ chunks.push(value);
1316
+ }
1317
+ }
1318
+ const merged = new Uint8Array(total);
1319
+ let offset = 0;
1320
+ for (const c of chunks) {
1321
+ merged.set(c, offset);
1322
+ offset += c.byteLength;
1323
+ }
1324
+ return merged;
1325
+ }
1326
+ var HttpError = class extends Error {
1327
+ constructor(status, statusText, body) {
1328
+ super(`HTTP ${status} ${statusText}: ${body}`);
1329
+ this.status = status;
1330
+ this.statusText = statusText;
1331
+ this.body = body;
1332
+ this.name = "HttpError";
1333
+ }
1334
+ };
1335
+ var AgentsClient = class {
1336
+ constructor(config) {
1337
+ this.config = config;
1338
+ if (!config.baseUrl) throw new Error("baseUrl is required");
1339
+ }
1340
+ headers(extra) {
1341
+ const h = { "Content-Type": "application/json" };
1342
+ if (this.config.apiKey) h["Authorization"] = `Bearer ${this.config.apiKey}`;
1343
+ if (this.config.tenant) h["x-rapidapi-user"] = this.config.tenant;
1344
+ return { ...h, ...extra ?? {} };
1345
+ }
1346
+ async request(method, path, body, headerOverride) {
1347
+ const url = this.config.baseUrl.replace(/\/$/, "") + path;
1348
+ const controller = new AbortController();
1349
+ const timeout = setTimeout(
1350
+ () => controller.abort(),
1351
+ this.config.timeoutMs ?? 12e4
1352
+ );
1353
+ try {
1354
+ const init = {
1355
+ method,
1356
+ headers: this.headers(headerOverride),
1357
+ signal: controller.signal
1358
+ };
1359
+ if (body !== void 0) init.body = JSON.stringify(body);
1360
+ const resp = await fetch(url, init);
1361
+ if (resp.status === 204) return null;
1362
+ const bytes = await _boundedRead(resp);
1363
+ const text = new TextDecoder().decode(bytes);
1364
+ if (!resp.ok) {
1365
+ throw new HttpError(resp.status, resp.statusText, text);
1366
+ }
1367
+ return text ? JSON.parse(text) : null;
1368
+ } finally {
1369
+ clearTimeout(timeout);
1370
+ }
1371
+ }
1372
+ // ── CRUD ────────────────────────────────────────────────────────
1373
+ async create(input) {
1374
+ const body = {
1375
+ name: input.name,
1376
+ wauldo_toml: input.wauldoToml,
1377
+ description: input.description ?? ""
1378
+ };
1379
+ if (input.agentsMd !== void 0) body.agents_md = input.agentsMd;
1380
+ if (input.mcpJson !== void 0) body.mcp_json = input.mcpJson;
1381
+ if (input.preset !== void 0) body.preset = input.preset;
1382
+ return await this.request("POST", "/v1/agents", body);
1383
+ }
1384
+ async list(limit = 20, offset = 0) {
1385
+ return await this.request(
1386
+ "GET",
1387
+ `/v1/agents?limit=${limit}&offset=${offset}`
1388
+ );
1389
+ }
1390
+ async get(agentId) {
1391
+ return await this.request("GET", `/v1/agents/${agentId}`);
1392
+ }
1393
+ async update(agentId, patch) {
1394
+ const body = {};
1395
+ if (patch.description !== void 0) body.description = patch.description;
1396
+ if (patch.wauldoToml !== void 0) body.wauldo_toml = patch.wauldoToml;
1397
+ if (patch.agentsMd !== void 0) body.agents_md = patch.agentsMd;
1398
+ if (patch.mcpJson !== void 0) body.mcp_json = patch.mcpJson;
1399
+ if (patch.preset !== void 0) body.preset = patch.preset;
1400
+ return await this.request("PATCH", `/v1/agents/${agentId}`, body);
1401
+ }
1402
+ async delete(agentId) {
1403
+ await this.request("DELETE", `/v1/agents/${agentId}`);
1404
+ }
1405
+ // ── Runs ────────────────────────────────────────────────────────
1406
+ async run(agentId, input, verificationMode, factCheckMode) {
1407
+ if (!input) throw new Error("input is required");
1408
+ const body = { input };
1409
+ if (verificationMode) body.verification_mode = verificationMode;
1410
+ if (factCheckMode) body.fact_check_mode = factCheckMode;
1411
+ return await this.request(
1412
+ "POST",
1413
+ `/v1/agents/${agentId}/runs`,
1414
+ body
1415
+ );
1416
+ }
1417
+ async a2aInvoke(agentId, input, trace, verificationMode, factCheckMode) {
1418
+ if (!input) throw new Error("input is required");
1419
+ const body = { input };
1420
+ if (verificationMode) body.verification_mode = verificationMode;
1421
+ if (factCheckMode) body.fact_check_mode = factCheckMode;
1422
+ const extraHeaders = {};
1423
+ if (trace && trace.length > 0) extraHeaders["x-a2a-trace"] = trace.join(",");
1424
+ return await this.request(
1425
+ "POST",
1426
+ `/v1/a2a/${agentId}`,
1427
+ body,
1428
+ extraHeaders
1429
+ );
1430
+ }
1431
+ // ── Tasks (poll + stream) ───────────────────────────────────────
1432
+ /** `GET /v1/tasks/:id` — fetch the current state of a task. */
1433
+ async getTask(taskId) {
1434
+ return await this.request("GET", `/v1/tasks/${taskId}`);
1435
+ }
1436
+ /** `DELETE /v1/tasks/:id` — cancel a queued or running task. */
1437
+ async cancelTask(taskId) {
1438
+ await this.request("DELETE", `/v1/tasks/${taskId}`);
1439
+ }
1440
+ /**
1441
+ * Poll `getTask` until the task reaches a terminal status. Resolves
1442
+ * with the final Task snapshot. Rejects with `Error("timeout")` if
1443
+ * the task is still running after `timeoutMs`. Use `streamTask` when
1444
+ * you need event-by-event progress instead of a single final state.
1445
+ */
1446
+ async waitForTask(taskId, opts = {}) {
1447
+ const timeoutMs = opts.timeoutMs ?? 18e4;
1448
+ const pollIntervalMs = opts.pollIntervalMs ?? 2e3;
1449
+ const deadline = Date.now() + timeoutMs;
1450
+ while (true) {
1451
+ const task = await this.getTask(taskId);
1452
+ if (isTerminalStatus(task.status)) return task;
1453
+ if (Date.now() >= deadline) {
1454
+ throw new Error(
1455
+ `task ${taskId} still in status '${task.status}' after ${timeoutMs}ms`
1456
+ );
1457
+ }
1458
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
1459
+ }
1460
+ }
1461
+ /**
1462
+ * Subscribe to `GET /v1/tasks/:id/stream` and yield typed
1463
+ * StateTransition events as each workflow state completes. The
1464
+ * generator closes when the upstream stream closes (task reached
1465
+ * terminal status) or on connection error.
1466
+ *
1467
+ * @example
1468
+ * ```ts
1469
+ * for await (const event of agents.streamTask(run.task_id)) {
1470
+ * console.log(event.state_name, event.duration_ms);
1471
+ * }
1472
+ * ```
1473
+ */
1474
+ async *streamTask(taskId) {
1475
+ const url = this.config.baseUrl.replace(/\/$/, "") + `/v1/tasks/${taskId}/stream`;
1476
+ const controller = new AbortController();
1477
+ const resp = await fetch(url, {
1478
+ method: "GET",
1479
+ headers: this.headers({ Accept: "text/event-stream" }),
1480
+ signal: controller.signal
1481
+ });
1482
+ if (!resp.ok) {
1483
+ const text = await resp.text().catch(() => "");
1484
+ throw new HttpError(resp.status, resp.statusText, text);
1485
+ }
1486
+ if (!resp.body) return;
1487
+ const reader = resp.body.getReader();
1488
+ const decoder = new TextDecoder();
1489
+ let buffer = "";
1490
+ try {
1491
+ while (true) {
1492
+ const { value, done } = await reader.read();
1493
+ if (done) break;
1494
+ buffer += decoder.decode(value, { stream: true });
1495
+ const lines = buffer.split("\n");
1496
+ buffer = lines.pop() ?? "";
1497
+ for (const line of lines) {
1498
+ const trimmed = line.trimEnd().replace(/\r$/, "");
1499
+ if (!trimmed.startsWith("data:")) continue;
1500
+ const payload = trimmed.slice(5).trim();
1501
+ if (!payload) continue;
1502
+ try {
1503
+ const obj = JSON.parse(payload);
1504
+ yield obj;
1505
+ } catch {
1506
+ }
1507
+ }
1508
+ }
1509
+ } finally {
1510
+ try {
1511
+ controller.abort();
1512
+ } catch {
1513
+ }
1514
+ }
1515
+ }
1516
+ };
1287
1517
  // Annotate the CommonJS export names for ESM import in node:
1288
1518
  0 && (module.exports = {
1289
1519
  AgentClient,
1520
+ AgentsClient,
1290
1521
  ConnectionError,
1291
1522
  Conversation,
1292
1523
  HttpClient,
1524
+ HttpError,
1293
1525
  MockHttpClient,
1294
1526
  ServerError,
1295
1527
  TimeoutError,
@@ -1298,5 +1530,6 @@ function guardIsBlocked(response) {
1298
1530
  WauldoError,
1299
1531
  chatContent,
1300
1532
  guardIsBlocked,
1301
- guardIsSafe
1533
+ guardIsSafe,
1534
+ isTerminalStatus
1302
1535
  });
package/dist/index.mjs CHANGED
@@ -1246,11 +1246,240 @@ function guardIsSafe(response) {
1246
1246
  function guardIsBlocked(response) {
1247
1247
  return response.action === "block";
1248
1248
  }
1249
+
1250
+ // src/agents.ts
1251
+ var MAX_RESPONSE_SIZE = 10 * 1024 * 1024;
1252
+ function isTerminalStatus(s) {
1253
+ return s === "completed" || s === "failed" || s === "cancelled";
1254
+ }
1255
+ async function _boundedRead(resp, limit = MAX_RESPONSE_SIZE) {
1256
+ if (!resp.body) return new Uint8Array(0);
1257
+ const reader = resp.body.getReader();
1258
+ const chunks = [];
1259
+ let total = 0;
1260
+ while (true) {
1261
+ const { done, value } = await reader.read();
1262
+ if (done) break;
1263
+ if (value) {
1264
+ total += value.byteLength;
1265
+ if (total > limit) {
1266
+ try {
1267
+ await reader.cancel();
1268
+ } catch {
1269
+ }
1270
+ throw new Error(
1271
+ `response body too large: >${limit} bytes`
1272
+ );
1273
+ }
1274
+ chunks.push(value);
1275
+ }
1276
+ }
1277
+ const merged = new Uint8Array(total);
1278
+ let offset = 0;
1279
+ for (const c of chunks) {
1280
+ merged.set(c, offset);
1281
+ offset += c.byteLength;
1282
+ }
1283
+ return merged;
1284
+ }
1285
+ var HttpError = class extends Error {
1286
+ constructor(status, statusText, body) {
1287
+ super(`HTTP ${status} ${statusText}: ${body}`);
1288
+ this.status = status;
1289
+ this.statusText = statusText;
1290
+ this.body = body;
1291
+ this.name = "HttpError";
1292
+ }
1293
+ };
1294
+ var AgentsClient = class {
1295
+ constructor(config) {
1296
+ this.config = config;
1297
+ if (!config.baseUrl) throw new Error("baseUrl is required");
1298
+ }
1299
+ headers(extra) {
1300
+ const h = { "Content-Type": "application/json" };
1301
+ if (this.config.apiKey) h["Authorization"] = `Bearer ${this.config.apiKey}`;
1302
+ if (this.config.tenant) h["x-rapidapi-user"] = this.config.tenant;
1303
+ return { ...h, ...extra ?? {} };
1304
+ }
1305
+ async request(method, path, body, headerOverride) {
1306
+ const url = this.config.baseUrl.replace(/\/$/, "") + path;
1307
+ const controller = new AbortController();
1308
+ const timeout = setTimeout(
1309
+ () => controller.abort(),
1310
+ this.config.timeoutMs ?? 12e4
1311
+ );
1312
+ try {
1313
+ const init = {
1314
+ method,
1315
+ headers: this.headers(headerOverride),
1316
+ signal: controller.signal
1317
+ };
1318
+ if (body !== void 0) init.body = JSON.stringify(body);
1319
+ const resp = await fetch(url, init);
1320
+ if (resp.status === 204) return null;
1321
+ const bytes = await _boundedRead(resp);
1322
+ const text = new TextDecoder().decode(bytes);
1323
+ if (!resp.ok) {
1324
+ throw new HttpError(resp.status, resp.statusText, text);
1325
+ }
1326
+ return text ? JSON.parse(text) : null;
1327
+ } finally {
1328
+ clearTimeout(timeout);
1329
+ }
1330
+ }
1331
+ // ── CRUD ────────────────────────────────────────────────────────
1332
+ async create(input) {
1333
+ const body = {
1334
+ name: input.name,
1335
+ wauldo_toml: input.wauldoToml,
1336
+ description: input.description ?? ""
1337
+ };
1338
+ if (input.agentsMd !== void 0) body.agents_md = input.agentsMd;
1339
+ if (input.mcpJson !== void 0) body.mcp_json = input.mcpJson;
1340
+ if (input.preset !== void 0) body.preset = input.preset;
1341
+ return await this.request("POST", "/v1/agents", body);
1342
+ }
1343
+ async list(limit = 20, offset = 0) {
1344
+ return await this.request(
1345
+ "GET",
1346
+ `/v1/agents?limit=${limit}&offset=${offset}`
1347
+ );
1348
+ }
1349
+ async get(agentId) {
1350
+ return await this.request("GET", `/v1/agents/${agentId}`);
1351
+ }
1352
+ async update(agentId, patch) {
1353
+ const body = {};
1354
+ if (patch.description !== void 0) body.description = patch.description;
1355
+ if (patch.wauldoToml !== void 0) body.wauldo_toml = patch.wauldoToml;
1356
+ if (patch.agentsMd !== void 0) body.agents_md = patch.agentsMd;
1357
+ if (patch.mcpJson !== void 0) body.mcp_json = patch.mcpJson;
1358
+ if (patch.preset !== void 0) body.preset = patch.preset;
1359
+ return await this.request("PATCH", `/v1/agents/${agentId}`, body);
1360
+ }
1361
+ async delete(agentId) {
1362
+ await this.request("DELETE", `/v1/agents/${agentId}`);
1363
+ }
1364
+ // ── Runs ────────────────────────────────────────────────────────
1365
+ async run(agentId, input, verificationMode, factCheckMode) {
1366
+ if (!input) throw new Error("input is required");
1367
+ const body = { input };
1368
+ if (verificationMode) body.verification_mode = verificationMode;
1369
+ if (factCheckMode) body.fact_check_mode = factCheckMode;
1370
+ return await this.request(
1371
+ "POST",
1372
+ `/v1/agents/${agentId}/runs`,
1373
+ body
1374
+ );
1375
+ }
1376
+ async a2aInvoke(agentId, input, trace, verificationMode, factCheckMode) {
1377
+ if (!input) throw new Error("input is required");
1378
+ const body = { input };
1379
+ if (verificationMode) body.verification_mode = verificationMode;
1380
+ if (factCheckMode) body.fact_check_mode = factCheckMode;
1381
+ const extraHeaders = {};
1382
+ if (trace && trace.length > 0) extraHeaders["x-a2a-trace"] = trace.join(",");
1383
+ return await this.request(
1384
+ "POST",
1385
+ `/v1/a2a/${agentId}`,
1386
+ body,
1387
+ extraHeaders
1388
+ );
1389
+ }
1390
+ // ── Tasks (poll + stream) ───────────────────────────────────────
1391
+ /** `GET /v1/tasks/:id` — fetch the current state of a task. */
1392
+ async getTask(taskId) {
1393
+ return await this.request("GET", `/v1/tasks/${taskId}`);
1394
+ }
1395
+ /** `DELETE /v1/tasks/:id` — cancel a queued or running task. */
1396
+ async cancelTask(taskId) {
1397
+ await this.request("DELETE", `/v1/tasks/${taskId}`);
1398
+ }
1399
+ /**
1400
+ * Poll `getTask` until the task reaches a terminal status. Resolves
1401
+ * with the final Task snapshot. Rejects with `Error("timeout")` if
1402
+ * the task is still running after `timeoutMs`. Use `streamTask` when
1403
+ * you need event-by-event progress instead of a single final state.
1404
+ */
1405
+ async waitForTask(taskId, opts = {}) {
1406
+ const timeoutMs = opts.timeoutMs ?? 18e4;
1407
+ const pollIntervalMs = opts.pollIntervalMs ?? 2e3;
1408
+ const deadline = Date.now() + timeoutMs;
1409
+ while (true) {
1410
+ const task = await this.getTask(taskId);
1411
+ if (isTerminalStatus(task.status)) return task;
1412
+ if (Date.now() >= deadline) {
1413
+ throw new Error(
1414
+ `task ${taskId} still in status '${task.status}' after ${timeoutMs}ms`
1415
+ );
1416
+ }
1417
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
1418
+ }
1419
+ }
1420
+ /**
1421
+ * Subscribe to `GET /v1/tasks/:id/stream` and yield typed
1422
+ * StateTransition events as each workflow state completes. The
1423
+ * generator closes when the upstream stream closes (task reached
1424
+ * terminal status) or on connection error.
1425
+ *
1426
+ * @example
1427
+ * ```ts
1428
+ * for await (const event of agents.streamTask(run.task_id)) {
1429
+ * console.log(event.state_name, event.duration_ms);
1430
+ * }
1431
+ * ```
1432
+ */
1433
+ async *streamTask(taskId) {
1434
+ const url = this.config.baseUrl.replace(/\/$/, "") + `/v1/tasks/${taskId}/stream`;
1435
+ const controller = new AbortController();
1436
+ const resp = await fetch(url, {
1437
+ method: "GET",
1438
+ headers: this.headers({ Accept: "text/event-stream" }),
1439
+ signal: controller.signal
1440
+ });
1441
+ if (!resp.ok) {
1442
+ const text = await resp.text().catch(() => "");
1443
+ throw new HttpError(resp.status, resp.statusText, text);
1444
+ }
1445
+ if (!resp.body) return;
1446
+ const reader = resp.body.getReader();
1447
+ const decoder = new TextDecoder();
1448
+ let buffer = "";
1449
+ try {
1450
+ while (true) {
1451
+ const { value, done } = await reader.read();
1452
+ if (done) break;
1453
+ buffer += decoder.decode(value, { stream: true });
1454
+ const lines = buffer.split("\n");
1455
+ buffer = lines.pop() ?? "";
1456
+ for (const line of lines) {
1457
+ const trimmed = line.trimEnd().replace(/\r$/, "");
1458
+ if (!trimmed.startsWith("data:")) continue;
1459
+ const payload = trimmed.slice(5).trim();
1460
+ if (!payload) continue;
1461
+ try {
1462
+ const obj = JSON.parse(payload);
1463
+ yield obj;
1464
+ } catch {
1465
+ }
1466
+ }
1467
+ }
1468
+ } finally {
1469
+ try {
1470
+ controller.abort();
1471
+ } catch {
1472
+ }
1473
+ }
1474
+ }
1475
+ };
1249
1476
  export {
1250
1477
  AgentClient,
1478
+ AgentsClient,
1251
1479
  ConnectionError,
1252
1480
  Conversation,
1253
1481
  HttpClient,
1482
+ HttpError,
1254
1483
  MockHttpClient,
1255
1484
  ServerError,
1256
1485
  TimeoutError,
@@ -1259,5 +1488,6 @@ export {
1259
1488
  WauldoError,
1260
1489
  chatContent,
1261
1490
  guardIsBlocked,
1262
- guardIsSafe
1491
+ guardIsSafe,
1492
+ isTerminalStatus
1263
1493
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wauldo",
3
- "version": "0.7.2",
3
+ "version": "0.9.0",
4
4
  "description": "Official TypeScript SDK for Wauldo — Verified AI answers from your documents",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",