wauldo 0.7.1 → 0.8.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
@@ -593,6 +593,7 @@ declare class MockHttpClient {
593
593
  system?: string;
594
594
  model?: string;
595
595
  }): Conversation;
596
+ guard(text: string, sourceContext: string, mode?: GuardMode, _options?: RequestOptions): Promise<GuardResponse>;
596
597
  ragAsk(question: string, text: string, source?: string): Promise<string>;
597
598
  private record;
598
599
  }
@@ -643,4 +644,175 @@ declare class ToolNotFoundError extends WauldoError {
643
644
  constructor(toolName: string);
644
645
  }
645
646
 
646
- 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"): Promise<AgentRunResponse>;
787
+ a2aInvoke(agentId: string, input: string, trace?: string[], verificationMode?: "strict" | "balanced" | "permissive"): 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
@@ -593,6 +593,7 @@ declare class MockHttpClient {
593
593
  system?: string;
594
594
  model?: string;
595
595
  }): Conversation;
596
+ guard(text: string, sourceContext: string, mode?: GuardMode, _options?: RequestOptions): Promise<GuardResponse>;
596
597
  ragAsk(question: string, text: string, source?: string): Promise<string>;
597
598
  private record;
598
599
  }
@@ -643,4 +644,175 @@ declare class ToolNotFoundError extends WauldoError {
643
644
  constructor(toolName: string);
644
645
  }
645
646
 
646
- 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"): Promise<AgentRunResponse>;
787
+ a2aInvoke(agentId: string, input: string, trace?: string[], verificationMode?: "strict" | "balanced" | "permissive"): 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
 
@@ -1235,6 +1238,34 @@ var MockHttpClient = class {
1235
1238
  this.record("conversation", options);
1236
1239
  return new Conversation(this, options);
1237
1240
  }
1241
+ async guard(text, sourceContext, mode = "lexical", _options) {
1242
+ this.record("guard", text, sourceContext, mode);
1243
+ const textNums = new Set(text.match(/\b\d+(?:\.\d+)?\b/g) ?? []);
1244
+ const srcNums = new Set(sourceContext.match(/\b\d+(?:\.\d+)?\b/g) ?? []);
1245
+ const mismatch = textNums.size > 0 && srcNums.size > 0 && [...textNums].some((n) => !srcNums.has(n));
1246
+ if (mismatch) {
1247
+ return {
1248
+ verdict: "rejected",
1249
+ action: "block",
1250
+ hallucination_rate: 1,
1251
+ mode,
1252
+ total_claims: 1,
1253
+ supported_claims: 0,
1254
+ confidence: 0,
1255
+ claims: [{ text, supported: false, confidence: 0.3, verdict: "rejected", action: "block", reason: "numerical_mismatch" }]
1256
+ };
1257
+ }
1258
+ return {
1259
+ verdict: "verified",
1260
+ action: "allow",
1261
+ hallucination_rate: 0,
1262
+ mode,
1263
+ total_claims: 1,
1264
+ supported_claims: 1,
1265
+ confidence: 0.95,
1266
+ claims: [{ text, supported: true, confidence: 0.95, verdict: "verified", action: "allow" }]
1267
+ };
1268
+ }
1238
1269
  async ragAsk(question, text, source = "document") {
1239
1270
  this.record("ragAsk", question, text, source);
1240
1271
  await this.ragUpload(text, source);
@@ -1256,12 +1287,239 @@ function guardIsSafe(response) {
1256
1287
  function guardIsBlocked(response) {
1257
1288
  return response.action === "block";
1258
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) {
1407
+ if (!input) throw new Error("input is required");
1408
+ const body = { input };
1409
+ if (verificationMode) body.verification_mode = verificationMode;
1410
+ return await this.request(
1411
+ "POST",
1412
+ `/v1/agents/${agentId}/runs`,
1413
+ body
1414
+ );
1415
+ }
1416
+ async a2aInvoke(agentId, input, trace, verificationMode) {
1417
+ if (!input) throw new Error("input is required");
1418
+ const body = { input };
1419
+ if (verificationMode) body.verification_mode = verificationMode;
1420
+ const extraHeaders = {};
1421
+ if (trace && trace.length > 0) extraHeaders["x-a2a-trace"] = trace.join(",");
1422
+ return await this.request(
1423
+ "POST",
1424
+ `/v1/a2a/${agentId}`,
1425
+ body,
1426
+ extraHeaders
1427
+ );
1428
+ }
1429
+ // ── Tasks (poll + stream) ───────────────────────────────────────
1430
+ /** `GET /v1/tasks/:id` — fetch the current state of a task. */
1431
+ async getTask(taskId) {
1432
+ return await this.request("GET", `/v1/tasks/${taskId}`);
1433
+ }
1434
+ /** `DELETE /v1/tasks/:id` — cancel a queued or running task. */
1435
+ async cancelTask(taskId) {
1436
+ await this.request("DELETE", `/v1/tasks/${taskId}`);
1437
+ }
1438
+ /**
1439
+ * Poll `getTask` until the task reaches a terminal status. Resolves
1440
+ * with the final Task snapshot. Rejects with `Error("timeout")` if
1441
+ * the task is still running after `timeoutMs`. Use `streamTask` when
1442
+ * you need event-by-event progress instead of a single final state.
1443
+ */
1444
+ async waitForTask(taskId, opts = {}) {
1445
+ const timeoutMs = opts.timeoutMs ?? 18e4;
1446
+ const pollIntervalMs = opts.pollIntervalMs ?? 2e3;
1447
+ const deadline = Date.now() + timeoutMs;
1448
+ while (true) {
1449
+ const task = await this.getTask(taskId);
1450
+ if (isTerminalStatus(task.status)) return task;
1451
+ if (Date.now() >= deadline) {
1452
+ throw new Error(
1453
+ `task ${taskId} still in status '${task.status}' after ${timeoutMs}ms`
1454
+ );
1455
+ }
1456
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
1457
+ }
1458
+ }
1459
+ /**
1460
+ * Subscribe to `GET /v1/tasks/:id/stream` and yield typed
1461
+ * StateTransition events as each workflow state completes. The
1462
+ * generator closes when the upstream stream closes (task reached
1463
+ * terminal status) or on connection error.
1464
+ *
1465
+ * @example
1466
+ * ```ts
1467
+ * for await (const event of agents.streamTask(run.task_id)) {
1468
+ * console.log(event.state_name, event.duration_ms);
1469
+ * }
1470
+ * ```
1471
+ */
1472
+ async *streamTask(taskId) {
1473
+ const url = this.config.baseUrl.replace(/\/$/, "") + `/v1/tasks/${taskId}/stream`;
1474
+ const controller = new AbortController();
1475
+ const resp = await fetch(url, {
1476
+ method: "GET",
1477
+ headers: this.headers({ Accept: "text/event-stream" }),
1478
+ signal: controller.signal
1479
+ });
1480
+ if (!resp.ok) {
1481
+ const text = await resp.text().catch(() => "");
1482
+ throw new HttpError(resp.status, resp.statusText, text);
1483
+ }
1484
+ if (!resp.body) return;
1485
+ const reader = resp.body.getReader();
1486
+ const decoder = new TextDecoder();
1487
+ let buffer = "";
1488
+ try {
1489
+ while (true) {
1490
+ const { value, done } = await reader.read();
1491
+ if (done) break;
1492
+ buffer += decoder.decode(value, { stream: true });
1493
+ const lines = buffer.split("\n");
1494
+ buffer = lines.pop() ?? "";
1495
+ for (const line of lines) {
1496
+ const trimmed = line.trimEnd().replace(/\r$/, "");
1497
+ if (!trimmed.startsWith("data:")) continue;
1498
+ const payload = trimmed.slice(5).trim();
1499
+ if (!payload) continue;
1500
+ try {
1501
+ const obj = JSON.parse(payload);
1502
+ yield obj;
1503
+ } catch {
1504
+ }
1505
+ }
1506
+ }
1507
+ } finally {
1508
+ try {
1509
+ controller.abort();
1510
+ } catch {
1511
+ }
1512
+ }
1513
+ }
1514
+ };
1259
1515
  // Annotate the CommonJS export names for ESM import in node:
1260
1516
  0 && (module.exports = {
1261
1517
  AgentClient,
1518
+ AgentsClient,
1262
1519
  ConnectionError,
1263
1520
  Conversation,
1264
1521
  HttpClient,
1522
+ HttpError,
1265
1523
  MockHttpClient,
1266
1524
  ServerError,
1267
1525
  TimeoutError,
@@ -1270,5 +1528,6 @@ function guardIsBlocked(response) {
1270
1528
  WauldoError,
1271
1529
  chatContent,
1272
1530
  guardIsBlocked,
1273
- guardIsSafe
1531
+ guardIsSafe,
1532
+ isTerminalStatus
1274
1533
  });
package/dist/index.mjs CHANGED
@@ -1197,6 +1197,34 @@ var MockHttpClient = class {
1197
1197
  this.record("conversation", options);
1198
1198
  return new Conversation(this, options);
1199
1199
  }
1200
+ async guard(text, sourceContext, mode = "lexical", _options) {
1201
+ this.record("guard", text, sourceContext, mode);
1202
+ const textNums = new Set(text.match(/\b\d+(?:\.\d+)?\b/g) ?? []);
1203
+ const srcNums = new Set(sourceContext.match(/\b\d+(?:\.\d+)?\b/g) ?? []);
1204
+ const mismatch = textNums.size > 0 && srcNums.size > 0 && [...textNums].some((n) => !srcNums.has(n));
1205
+ if (mismatch) {
1206
+ return {
1207
+ verdict: "rejected",
1208
+ action: "block",
1209
+ hallucination_rate: 1,
1210
+ mode,
1211
+ total_claims: 1,
1212
+ supported_claims: 0,
1213
+ confidence: 0,
1214
+ claims: [{ text, supported: false, confidence: 0.3, verdict: "rejected", action: "block", reason: "numerical_mismatch" }]
1215
+ };
1216
+ }
1217
+ return {
1218
+ verdict: "verified",
1219
+ action: "allow",
1220
+ hallucination_rate: 0,
1221
+ mode,
1222
+ total_claims: 1,
1223
+ supported_claims: 1,
1224
+ confidence: 0.95,
1225
+ claims: [{ text, supported: true, confidence: 0.95, verdict: "verified", action: "allow" }]
1226
+ };
1227
+ }
1200
1228
  async ragAsk(question, text, source = "document") {
1201
1229
  this.record("ragAsk", question, text, source);
1202
1230
  await this.ragUpload(text, source);
@@ -1218,11 +1246,238 @@ function guardIsSafe(response) {
1218
1246
  function guardIsBlocked(response) {
1219
1247
  return response.action === "block";
1220
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) {
1366
+ if (!input) throw new Error("input is required");
1367
+ const body = { input };
1368
+ if (verificationMode) body.verification_mode = verificationMode;
1369
+ return await this.request(
1370
+ "POST",
1371
+ `/v1/agents/${agentId}/runs`,
1372
+ body
1373
+ );
1374
+ }
1375
+ async a2aInvoke(agentId, input, trace, verificationMode) {
1376
+ if (!input) throw new Error("input is required");
1377
+ const body = { input };
1378
+ if (verificationMode) body.verification_mode = verificationMode;
1379
+ const extraHeaders = {};
1380
+ if (trace && trace.length > 0) extraHeaders["x-a2a-trace"] = trace.join(",");
1381
+ return await this.request(
1382
+ "POST",
1383
+ `/v1/a2a/${agentId}`,
1384
+ body,
1385
+ extraHeaders
1386
+ );
1387
+ }
1388
+ // ── Tasks (poll + stream) ───────────────────────────────────────
1389
+ /** `GET /v1/tasks/:id` — fetch the current state of a task. */
1390
+ async getTask(taskId) {
1391
+ return await this.request("GET", `/v1/tasks/${taskId}`);
1392
+ }
1393
+ /** `DELETE /v1/tasks/:id` — cancel a queued or running task. */
1394
+ async cancelTask(taskId) {
1395
+ await this.request("DELETE", `/v1/tasks/${taskId}`);
1396
+ }
1397
+ /**
1398
+ * Poll `getTask` until the task reaches a terminal status. Resolves
1399
+ * with the final Task snapshot. Rejects with `Error("timeout")` if
1400
+ * the task is still running after `timeoutMs`. Use `streamTask` when
1401
+ * you need event-by-event progress instead of a single final state.
1402
+ */
1403
+ async waitForTask(taskId, opts = {}) {
1404
+ const timeoutMs = opts.timeoutMs ?? 18e4;
1405
+ const pollIntervalMs = opts.pollIntervalMs ?? 2e3;
1406
+ const deadline = Date.now() + timeoutMs;
1407
+ while (true) {
1408
+ const task = await this.getTask(taskId);
1409
+ if (isTerminalStatus(task.status)) return task;
1410
+ if (Date.now() >= deadline) {
1411
+ throw new Error(
1412
+ `task ${taskId} still in status '${task.status}' after ${timeoutMs}ms`
1413
+ );
1414
+ }
1415
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
1416
+ }
1417
+ }
1418
+ /**
1419
+ * Subscribe to `GET /v1/tasks/:id/stream` and yield typed
1420
+ * StateTransition events as each workflow state completes. The
1421
+ * generator closes when the upstream stream closes (task reached
1422
+ * terminal status) or on connection error.
1423
+ *
1424
+ * @example
1425
+ * ```ts
1426
+ * for await (const event of agents.streamTask(run.task_id)) {
1427
+ * console.log(event.state_name, event.duration_ms);
1428
+ * }
1429
+ * ```
1430
+ */
1431
+ async *streamTask(taskId) {
1432
+ const url = this.config.baseUrl.replace(/\/$/, "") + `/v1/tasks/${taskId}/stream`;
1433
+ const controller = new AbortController();
1434
+ const resp = await fetch(url, {
1435
+ method: "GET",
1436
+ headers: this.headers({ Accept: "text/event-stream" }),
1437
+ signal: controller.signal
1438
+ });
1439
+ if (!resp.ok) {
1440
+ const text = await resp.text().catch(() => "");
1441
+ throw new HttpError(resp.status, resp.statusText, text);
1442
+ }
1443
+ if (!resp.body) return;
1444
+ const reader = resp.body.getReader();
1445
+ const decoder = new TextDecoder();
1446
+ let buffer = "";
1447
+ try {
1448
+ while (true) {
1449
+ const { value, done } = await reader.read();
1450
+ if (done) break;
1451
+ buffer += decoder.decode(value, { stream: true });
1452
+ const lines = buffer.split("\n");
1453
+ buffer = lines.pop() ?? "";
1454
+ for (const line of lines) {
1455
+ const trimmed = line.trimEnd().replace(/\r$/, "");
1456
+ if (!trimmed.startsWith("data:")) continue;
1457
+ const payload = trimmed.slice(5).trim();
1458
+ if (!payload) continue;
1459
+ try {
1460
+ const obj = JSON.parse(payload);
1461
+ yield obj;
1462
+ } catch {
1463
+ }
1464
+ }
1465
+ }
1466
+ } finally {
1467
+ try {
1468
+ controller.abort();
1469
+ } catch {
1470
+ }
1471
+ }
1472
+ }
1473
+ };
1221
1474
  export {
1222
1475
  AgentClient,
1476
+ AgentsClient,
1223
1477
  ConnectionError,
1224
1478
  Conversation,
1225
1479
  HttpClient,
1480
+ HttpError,
1226
1481
  MockHttpClient,
1227
1482
  ServerError,
1228
1483
  TimeoutError,
@@ -1231,5 +1486,6 @@ export {
1231
1486
  WauldoError,
1232
1487
  chatContent,
1233
1488
  guardIsBlocked,
1234
- guardIsSafe
1489
+ guardIsSafe,
1490
+ isTerminalStatus
1235
1491
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wauldo",
3
- "version": "0.7.1",
3
+ "version": "0.8.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",