@komputer-ai/sdk 0.11.2 → 0.11.5

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.
@@ -0,0 +1,68 @@
1
+ .gitignore
2
+ docs/AgentListResponse.md
3
+ docs/AgentResponse.md
4
+ docs/AgentsApi.md
5
+ docs/ConnectorResponse.md
6
+ docs/ConnectorsApi.md
7
+ docs/CreateAgentRequest.md
8
+ docs/CreateConnectorRequest.md
9
+ docs/CreateMemoryRequest.md
10
+ docs/CreateScheduleAgentSpec.md
11
+ docs/CreateScheduleRequest.md
12
+ docs/CreateSecretRequest.md
13
+ docs/CreateSkillRequest.md
14
+ docs/MemoriesApi.md
15
+ docs/MemoryResponse.md
16
+ docs/OfficeListResponse.md
17
+ docs/OfficeMemberResponse.md
18
+ docs/OfficeResponse.md
19
+ docs/OfficesApi.md
20
+ docs/PatchAgentRequest.md
21
+ docs/PatchMemoryRequest.md
22
+ docs/PatchScheduleRequest.md
23
+ docs/PatchSkillRequest.md
24
+ docs/ScheduleListResponse.md
25
+ docs/ScheduleResponse.md
26
+ docs/SchedulesApi.md
27
+ docs/SecretListResponse.md
28
+ docs/SecretResponse.md
29
+ docs/SecretsApi.md
30
+ docs/SkillResponse.md
31
+ docs/SkillsApi.md
32
+ docs/TemplatesApi.md
33
+ docs/UpdateSecretRequest.md
34
+ src/apis/AgentsApi.ts
35
+ src/apis/ConnectorsApi.ts
36
+ src/apis/MemoriesApi.ts
37
+ src/apis/OfficesApi.ts
38
+ src/apis/SchedulesApi.ts
39
+ src/apis/SecretsApi.ts
40
+ src/apis/SkillsApi.ts
41
+ src/apis/TemplatesApi.ts
42
+ src/apis/index.ts
43
+ src/models/AgentListResponse.ts
44
+ src/models/AgentResponse.ts
45
+ src/models/ConnectorResponse.ts
46
+ src/models/CreateAgentRequest.ts
47
+ src/models/CreateConnectorRequest.ts
48
+ src/models/CreateMemoryRequest.ts
49
+ src/models/CreateScheduleAgentSpec.ts
50
+ src/models/CreateScheduleRequest.ts
51
+ src/models/CreateSecretRequest.ts
52
+ src/models/CreateSkillRequest.ts
53
+ src/models/MemoryResponse.ts
54
+ src/models/OfficeListResponse.ts
55
+ src/models/OfficeMemberResponse.ts
56
+ src/models/OfficeResponse.ts
57
+ src/models/PatchAgentRequest.ts
58
+ src/models/PatchMemoryRequest.ts
59
+ src/models/PatchScheduleRequest.ts
60
+ src/models/PatchSkillRequest.ts
61
+ src/models/ScheduleListResponse.ts
62
+ src/models/ScheduleResponse.ts
63
+ src/models/SecretListResponse.ts
64
+ src/models/SecretResponse.ts
65
+ src/models/SkillResponse.ts
66
+ src/models/UpdateSecretRequest.ts
67
+ src/models/index.ts
68
+ src/runtime.ts
@@ -0,0 +1 @@
1
+ 7.21.0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # komputer-ai TypeScript SDK
1
+ # @komputer-ai/sdk
2
2
 
3
- TypeScript/JavaScript client for the [komputer.ai](https://github.com/kontroloop-ai/komputer-ai) platform.
3
+ TypeScript SDK for the [komputer.ai](https://komputer.ai) platform. Create agents, send tasks, and stream real-time results.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,16 +8,9 @@ TypeScript/JavaScript client for the [komputer.ai](https://github.com/kontroloop
8
8
  npm install @komputer-ai/sdk
9
9
  ```
10
10
 
11
- Or install directly from the repository:
11
+ ## Quick start
12
12
 
13
- ```bash
14
- git clone https://github.com/kontroloop-ai/komputer-ai.git
15
- cd komputer-ai/komputer-sdk/typescript && npm install && npm run build
16
- ```
17
-
18
- ## Quick Start
19
-
20
- ```typescript
13
+ ```ts
21
14
  import { KomputerClient } from "@komputer-ai/sdk";
22
15
 
23
16
  const client = new KomputerClient("http://localhost:8080");
@@ -25,123 +18,126 @@ const client = new KomputerClient("http://localhost:8080");
25
18
  // Create an agent
26
19
  const agent = await client.createAgent({
27
20
  name: "my-agent",
28
- instructions: "Summarize the latest Kubernetes release notes",
21
+ instructions: "Analyze our Kubernetes cluster",
29
22
  model: "claude-sonnet-4-6",
30
23
  });
31
24
 
32
- // Stream events as the agent works
33
- for await (const event of client.watchAgent("my-agent")) {
34
- if (event.type === "text") {
35
- console.log(event.payload.content);
36
- } else if (event.type === "task_completed") {
37
- console.log(`Done — cost: $${event.payload.cost_usd}`);
38
- break;
39
- }
25
+ // Stream events
26
+ for await (const event of await client.watchAgent("my-agent")) {
27
+ if (event.type === "text") console.log(event.payload.content);
28
+ if (event.type === "task_completed") break;
40
29
  }
41
30
  ```
42
31
 
43
- ## Usage
44
-
45
- ### Agents
32
+ ## Features
46
33
 
47
- ```typescript
48
- // Create
49
- await client.createAgent({ name: "researcher", instructions: "Research AI trends", model: "claude-sonnet-4-6" });
34
+ - Full REST API coverage: agents, memories, skills, schedules, secrets, connectors, offices, templates
35
+ - WebSocket event streaming with automatic history prefetch
36
+ - Idempotent create methods (safe to call twice without errors)
37
+ - TypeScript types for all request/response models
50
38
 
51
- // List
52
- const agents = await client.listAgents();
39
+ ## API
53
40
 
54
- // Get
55
- const agent = await client.getAgent("researcher");
41
+ ### Client
56
42
 
57
- // Update
58
- await client.patchAgent({ name: "researcher", model: "claude-haiku-4-5-20251001", lifecycle: "Sleep" });
43
+ ```ts
44
+ const client = new KomputerClient(baseUrl?: string);
45
+ ```
59
46
 
60
- // Cancel a running task
61
- await client.cancelAgentTask("researcher");
47
+ ### Agents
62
48
 
63
- // Delete
64
- await client.deleteAgent("researcher");
49
+ ```ts
50
+ await client.createAgent({ name, instructions, model?, ... })
51
+ await client.getAgent(name)
52
+ await client.listAgents()
53
+ await client.patchAgent({ name, instructions?, model?, ... })
54
+ await client.deleteAgent(name)
55
+ await client.cancelAgentTask(name)
56
+ await client.getAgentEvents(name)
57
+ const stream = await client.watchAgent(name) // WebSocket + history
65
58
  ```
66
59
 
67
60
  ### Memories
68
61
 
69
- ```typescript
70
- await client.createMemory({ name: "company-context", content: "We are a B2B SaaS company.", description: "Background" });
71
- await client.patchAgent({ name: "my-agent", memories: ["company-context"] });
72
-
73
- const memories = await client.listMemories();
74
- await client.patchMemory({ name: "company-context", content: "Updated context." });
75
- await client.deleteMemory("company-context");
62
+ ```ts
63
+ await client.createMemory({ name, content, description? })
64
+ await client.getMemory(name)
65
+ await client.listMemories()
66
+ await client.patchMemory({ name, content?, description? })
67
+ await client.deleteMemory(name)
76
68
  ```
77
69
 
78
70
  ### Skills
79
71
 
80
- ```typescript
81
- await client.createSkill({ name: "healthcheck", description: "Check service health", content: "curl -s http://api/healthz" });
82
- await client.patchAgent({ name: "my-agent", skills: ["healthcheck"] });
83
-
84
- const skills = await client.listSkills();
85
- await client.deleteSkill("healthcheck");
72
+ ```ts
73
+ await client.createSkill({ name, content, description })
74
+ await client.getSkill(name)
75
+ await client.listSkills()
76
+ await client.patchSkill({ name, content?, description? })
77
+ await client.deleteSkill(name)
86
78
  ```
87
79
 
88
80
  ### Schedules
89
81
 
90
- ```typescript
91
- await client.createSchedule({
92
- name: "daily-report",
93
- schedule: "0 9 * * *",
94
- instructions: "Generate a daily status report",
95
- timezone: "America/New_York",
96
- });
97
-
98
- const schedules = await client.listSchedules();
99
- await client.patchSchedule({ name: "daily-report", schedule: "0 10 * * *" });
100
- await client.deleteSchedule("daily-report");
82
+ ```ts
83
+ await client.createSchedule({ name, instructions, schedule, ... })
84
+ await client.getSchedule(name)
85
+ await client.listSchedules()
86
+ await client.patchSchedule({ name, schedule? })
87
+ await client.deleteSchedule(name)
101
88
  ```
102
89
 
103
90
  ### Secrets
104
91
 
105
- ```typescript
106
- await client.createSecret({ name: "api-keys", data: { GITHUB_TOKEN: "ghp_xxx", SLACK_TOKEN: "xoxb-xxx" } });
107
- await client.patchAgent({ name: "my-agent", secretRefs: ["api-keys"] });
108
-
109
- const secrets = await client.listSecrets();
110
- await client.deleteSecret("api-keys");
92
+ ```ts
93
+ await client.createSecret({ name, data })
94
+ await client.listSecrets()
95
+ await client.updateSecret({ name, data })
96
+ await client.deleteSecret(name)
111
97
  ```
112
98
 
113
99
  ### Connectors
114
100
 
115
- ```typescript
116
- await client.createConnector({ name: "slack", service: "slack", url: "https://mcp.slack.com", authType: "token" });
117
- await client.patchAgent({ name: "my-agent", connectors: ["slack"] });
118
-
119
- const connectors = await client.listConnectors();
120
- await client.deleteConnector("slack");
101
+ ```ts
102
+ await client.createConnector({ name, service, url, ... })
103
+ await client.getConnector(name)
104
+ await client.listConnectors()
105
+ await client.deleteConnector(name)
106
+ await client.listConnectorTools(name)
121
107
  ```
122
108
 
123
- ### Streaming Events
109
+ ### Event streaming
110
+
111
+ ```ts
112
+ import { KomputerClient } from "@komputer-ai/sdk";
113
+ import type { AgentEvent } from "@komputer-ai/sdk";
114
+
115
+ const stream = await client.watchAgent("my-agent");
124
116
 
125
- ```typescript
126
- for await (const event of client.watchAgent("my-agent")) {
117
+ for await (const event of stream) {
127
118
  switch (event.type) {
128
- case "task_started":
129
- console.log("Agent started working...");
130
- break;
131
- case "text":
132
- console.log(event.payload.content);
133
- break;
134
- case "tool_use":
135
- console.log(`Using tool: ${event.payload.name}`);
136
- break;
137
- case "task_completed":
138
- console.log(`Done — cost: $${event.payload.cost_usd}`);
139
- break;
140
- case "error":
141
- console.error(event.payload.error);
142
- break;
119
+ case "task_started": // Agent began working
120
+ case "thinking": // Model is reasoning
121
+ case "text": // Text output (event.payload.content)
122
+ case "tool_call": // Tool invocation
123
+ case "tool_result": // Tool response
124
+ case "task_completed": // Done (event.payload.cost_usd)
125
+ case "error": // Error occurred
143
126
  }
144
127
  }
145
128
  ```
146
129
 
147
- Event types: `task_started`, `thinking`, `tool_use`, `tool_result`, `text`, `task_completed`, `task_cancelled`, `error`.
130
+ ### Direct API access
131
+
132
+ For advanced use cases, the underlying generated API clients are available:
133
+
134
+ ```ts
135
+ import { AgentsApi, Configuration } from "@komputer-ai/sdk";
136
+
137
+ const config = new Configuration({ basePath: "http://localhost:8080/api/v1" });
138
+ const agents = new AgentsApi(config);
139
+ ```
140
+
141
+ ## License
142
+
143
+ MIT
package/dist/client.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * High-level convenience client for the komputer.ai API.
3
3
  *
4
- * Auto-generated by generate_client.py — do not edit manually.
4
+ * Hand-maintained — do not overwrite with generated output.
5
5
  *
6
6
  * @example
7
7
  * const client = new KomputerClient("http://localhost:8080");
@@ -124,7 +124,9 @@ export declare class KomputerClient {
124
124
  name: string;
125
125
  data: Record<string, string>;
126
126
  namespace?: string;
127
- }): Promise<import("./models").SecretResponse>;
127
+ }): Promise<import("./models").SecretResponse | {
128
+ [key: string]: string;
129
+ }>;
128
130
  updateSecret(params: {
129
131
  name: string;
130
132
  data: Record<string, string>;
@@ -169,5 +171,5 @@ export declare class KomputerClient {
169
171
  listTemplates(): Promise<{
170
172
  [key: string]: any;
171
173
  }>;
172
- watchAgent(name: string): AgentEventStream;
174
+ watchAgent(name: string): Promise<AgentEventStream>;
173
175
  }
package/dist/client.js CHANGED
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * High-level convenience client for the komputer.ai API.
4
4
  *
5
- * Auto-generated by generate_client.py — do not edit manually.
5
+ * Hand-maintained — do not overwrite with generated output.
6
6
  *
7
7
  * @example
8
8
  * const client = new KomputerClient("http://localhost:8080");
@@ -47,7 +47,15 @@ class KomputerClient {
47
47
  }
48
48
  createAgent(params) {
49
49
  return __awaiter(this, void 0, void 0, function* () {
50
- return this._agents.createAgent({ request: { connectors: params.connectors, instructions: params.instructions, lifecycle: params.lifecycle, memories: params.memories, model: params.model, name: params.name, namespace: params.namespace, officeManager: params.officeManager, role: params.role, secretRefs: params.secretRefs, skills: params.skills, systemPrompt: params.systemPrompt, templateRef: params.templateRef } });
50
+ try {
51
+ return yield this._agents.createAgent({ request: { connectors: params.connectors, instructions: params.instructions, lifecycle: params.lifecycle, memories: params.memories, model: params.model, name: params.name, namespace: params.namespace, officeManager: params.officeManager, role: params.role, secretRefs: params.secretRefs, skills: params.skills, systemPrompt: params.systemPrompt, templateRef: params.templateRef } });
52
+ }
53
+ catch (e) {
54
+ if (e instanceof runtime_1.ResponseError && e.response.status === 409) {
55
+ return this._agents.patchAgent({ name: params.name, request: { connectors: params.connectors, instructions: params.instructions, lifecycle: params.lifecycle, memories: params.memories, model: params.model, secretRefs: params.secretRefs, skills: params.skills, systemPrompt: params.systemPrompt, templateRef: params.templateRef } });
56
+ }
57
+ throw e;
58
+ }
51
59
  });
52
60
  }
53
61
  getAgent(name) {
@@ -83,7 +91,15 @@ class KomputerClient {
83
91
  }
84
92
  createMemory(params) {
85
93
  return __awaiter(this, void 0, void 0, function* () {
86
- return this._memories.createMemory({ request: { content: params.content, description: params.description, name: params.name, namespace: params.namespace } });
94
+ try {
95
+ return yield this._memories.createMemory({ request: { content: params.content, description: params.description, name: params.name, namespace: params.namespace } });
96
+ }
97
+ catch (e) {
98
+ if (e instanceof runtime_1.ResponseError && e.response.status === 409) {
99
+ return this._memories.patchMemory({ name: params.name, request: { content: params.content, description: params.description } });
100
+ }
101
+ throw e;
102
+ }
87
103
  });
88
104
  }
89
105
  getMemory(name) {
@@ -109,7 +125,15 @@ class KomputerClient {
109
125
  }
110
126
  createSkill(params) {
111
127
  return __awaiter(this, void 0, void 0, function* () {
112
- return this._skills.createSkill({ request: { content: params.content, description: params.description, name: params.name, namespace: params.namespace } });
128
+ try {
129
+ return yield this._skills.createSkill({ request: { content: params.content, description: params.description, name: params.name, namespace: params.namespace } });
130
+ }
131
+ catch (e) {
132
+ if (e instanceof runtime_1.ResponseError && e.response.status === 409) {
133
+ return this._skills.patchSkill({ name: params.name, request: { content: params.content, description: params.description } });
134
+ }
135
+ throw e;
136
+ }
113
137
  });
114
138
  }
115
139
  getSkill(name) {
@@ -135,7 +159,15 @@ class KomputerClient {
135
159
  }
136
160
  createSchedule(params) {
137
161
  return __awaiter(this, void 0, void 0, function* () {
138
- return this._schedules.createSchedule({ request: { agent: params.agent, agentName: params.agentName, autoDelete: params.autoDelete, instructions: params.instructions, keepAgents: params.keepAgents, name: params.name, namespace: params.namespace, schedule: params.schedule, timezone: params.timezone } });
162
+ try {
163
+ return yield this._schedules.createSchedule({ request: { agent: params.agent, agentName: params.agentName, autoDelete: params.autoDelete, instructions: params.instructions, keepAgents: params.keepAgents, name: params.name, namespace: params.namespace, schedule: params.schedule, timezone: params.timezone } });
164
+ }
165
+ catch (e) {
166
+ if (e instanceof runtime_1.ResponseError && e.response.status === 409) {
167
+ return this._schedules.patchSchedule({ name: params.name, request: { schedule: params.schedule } });
168
+ }
169
+ throw e;
170
+ }
139
171
  });
140
172
  }
141
173
  getSchedule(name) {
@@ -161,7 +193,15 @@ class KomputerClient {
161
193
  }
162
194
  createSecret(params) {
163
195
  return __awaiter(this, void 0, void 0, function* () {
164
- return this._secrets.createSecret({ request: { data: params.data, name: params.name, namespace: params.namespace } });
196
+ try {
197
+ return yield this._secrets.createSecret({ request: { data: params.data, name: params.name, namespace: params.namespace } });
198
+ }
199
+ catch (e) {
200
+ if (e instanceof runtime_1.ResponseError && e.response.status === 409) {
201
+ return this._secrets.updateSecret({ name: params.name, request: { data: params.data, namespace: params.namespace } });
202
+ }
203
+ throw e;
204
+ }
165
205
  });
166
206
  }
167
207
  updateSecret(params) {
@@ -229,8 +269,25 @@ class KomputerClient {
229
269
  }
230
270
  // --- WebSocket ---
231
271
  watchAgent(name) {
232
- const wsUrl = this._baseUrl.replace("http://", "ws://").replace("https://", "wss://");
233
- return new watch_1.AgentEventStream(wsUrl, name);
272
+ return __awaiter(this, void 0, void 0, function* () {
273
+ const wsUrl = this._baseUrl.replace("http://", "ws://").replace("https://", "wss://");
274
+ let history = [];
275
+ try {
276
+ const resp = yield this._agents.getAgentEvents({ name, limit: 200 });
277
+ if (resp && Array.isArray(resp.events)) {
278
+ history = resp.events.map((e) => ({
279
+ agentName: e.agentName || name,
280
+ type: e.type || "",
281
+ timestamp: e.timestamp || "",
282
+ payload: e.payload || {},
283
+ }));
284
+ }
285
+ }
286
+ catch (_a) {
287
+ // History fetch failed — proceed with live-only.
288
+ }
289
+ return new watch_1.AgentEventStream(wsUrl, name, history);
290
+ });
234
291
  }
235
292
  }
236
293
  exports.KomputerClient = KomputerClient;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * High-level convenience client for the komputer.ai API.
3
3
  *
4
- * Auto-generated by generate_client.py — do not edit manually.
4
+ * Hand-maintained — do not overwrite with generated output.
5
5
  *
6
6
  * @example
7
7
  * const client = new KomputerClient("http://localhost:8080");
@@ -124,7 +124,9 @@ export declare class KomputerClient {
124
124
  name: string;
125
125
  data: Record<string, string>;
126
126
  namespace?: string;
127
- }): Promise<import("./models").SecretResponse>;
127
+ }): Promise<import("./models").SecretResponse | {
128
+ [key: string]: string;
129
+ }>;
128
130
  updateSecret(params: {
129
131
  name: string;
130
132
  data: Record<string, string>;
@@ -169,5 +171,5 @@ export declare class KomputerClient {
169
171
  listTemplates(): Promise<{
170
172
  [key: string]: any;
171
173
  }>;
172
- watchAgent(name: string): AgentEventStream;
174
+ watchAgent(name: string): Promise<AgentEventStream>;
173
175
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * High-level convenience client for the komputer.ai API.
3
3
  *
4
- * Auto-generated by generate_client.py — do not edit manually.
4
+ * Hand-maintained — do not overwrite with generated output.
5
5
  *
6
6
  * @example
7
7
  * const client = new KomputerClient("http://localhost:8080");
@@ -20,7 +20,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
20
20
  step((generator = generator.apply(thisArg, _arguments || [])).next());
21
21
  });
22
22
  };
23
- import { Configuration } from "./runtime";
23
+ import { Configuration, ResponseError } from "./runtime";
24
24
  import { AgentsApi, ConnectorsApi, MemoriesApi, OfficesApi, SchedulesApi, SecretsApi, SkillsApi, TemplatesApi } from "./apis";
25
25
  import { AgentEventStream } from "./watch";
26
26
  export class KomputerClient {
@@ -44,7 +44,15 @@ export class KomputerClient {
44
44
  }
45
45
  createAgent(params) {
46
46
  return __awaiter(this, void 0, void 0, function* () {
47
- return this._agents.createAgent({ request: { connectors: params.connectors, instructions: params.instructions, lifecycle: params.lifecycle, memories: params.memories, model: params.model, name: params.name, namespace: params.namespace, officeManager: params.officeManager, role: params.role, secretRefs: params.secretRefs, skills: params.skills, systemPrompt: params.systemPrompt, templateRef: params.templateRef } });
47
+ try {
48
+ return yield this._agents.createAgent({ request: { connectors: params.connectors, instructions: params.instructions, lifecycle: params.lifecycle, memories: params.memories, model: params.model, name: params.name, namespace: params.namespace, officeManager: params.officeManager, role: params.role, secretRefs: params.secretRefs, skills: params.skills, systemPrompt: params.systemPrompt, templateRef: params.templateRef } });
49
+ }
50
+ catch (e) {
51
+ if (e instanceof ResponseError && e.response.status === 409) {
52
+ return this._agents.patchAgent({ name: params.name, request: { connectors: params.connectors, instructions: params.instructions, lifecycle: params.lifecycle, memories: params.memories, model: params.model, secretRefs: params.secretRefs, skills: params.skills, systemPrompt: params.systemPrompt, templateRef: params.templateRef } });
53
+ }
54
+ throw e;
55
+ }
48
56
  });
49
57
  }
50
58
  getAgent(name) {
@@ -80,7 +88,15 @@ export class KomputerClient {
80
88
  }
81
89
  createMemory(params) {
82
90
  return __awaiter(this, void 0, void 0, function* () {
83
- return this._memories.createMemory({ request: { content: params.content, description: params.description, name: params.name, namespace: params.namespace } });
91
+ try {
92
+ return yield this._memories.createMemory({ request: { content: params.content, description: params.description, name: params.name, namespace: params.namespace } });
93
+ }
94
+ catch (e) {
95
+ if (e instanceof ResponseError && e.response.status === 409) {
96
+ return this._memories.patchMemory({ name: params.name, request: { content: params.content, description: params.description } });
97
+ }
98
+ throw e;
99
+ }
84
100
  });
85
101
  }
86
102
  getMemory(name) {
@@ -106,7 +122,15 @@ export class KomputerClient {
106
122
  }
107
123
  createSkill(params) {
108
124
  return __awaiter(this, void 0, void 0, function* () {
109
- return this._skills.createSkill({ request: { content: params.content, description: params.description, name: params.name, namespace: params.namespace } });
125
+ try {
126
+ return yield this._skills.createSkill({ request: { content: params.content, description: params.description, name: params.name, namespace: params.namespace } });
127
+ }
128
+ catch (e) {
129
+ if (e instanceof ResponseError && e.response.status === 409) {
130
+ return this._skills.patchSkill({ name: params.name, request: { content: params.content, description: params.description } });
131
+ }
132
+ throw e;
133
+ }
110
134
  });
111
135
  }
112
136
  getSkill(name) {
@@ -132,7 +156,15 @@ export class KomputerClient {
132
156
  }
133
157
  createSchedule(params) {
134
158
  return __awaiter(this, void 0, void 0, function* () {
135
- return this._schedules.createSchedule({ request: { agent: params.agent, agentName: params.agentName, autoDelete: params.autoDelete, instructions: params.instructions, keepAgents: params.keepAgents, name: params.name, namespace: params.namespace, schedule: params.schedule, timezone: params.timezone } });
159
+ try {
160
+ return yield this._schedules.createSchedule({ request: { agent: params.agent, agentName: params.agentName, autoDelete: params.autoDelete, instructions: params.instructions, keepAgents: params.keepAgents, name: params.name, namespace: params.namespace, schedule: params.schedule, timezone: params.timezone } });
161
+ }
162
+ catch (e) {
163
+ if (e instanceof ResponseError && e.response.status === 409) {
164
+ return this._schedules.patchSchedule({ name: params.name, request: { schedule: params.schedule } });
165
+ }
166
+ throw e;
167
+ }
136
168
  });
137
169
  }
138
170
  getSchedule(name) {
@@ -158,7 +190,15 @@ export class KomputerClient {
158
190
  }
159
191
  createSecret(params) {
160
192
  return __awaiter(this, void 0, void 0, function* () {
161
- return this._secrets.createSecret({ request: { data: params.data, name: params.name, namespace: params.namespace } });
193
+ try {
194
+ return yield this._secrets.createSecret({ request: { data: params.data, name: params.name, namespace: params.namespace } });
195
+ }
196
+ catch (e) {
197
+ if (e instanceof ResponseError && e.response.status === 409) {
198
+ return this._secrets.updateSecret({ name: params.name, request: { data: params.data, namespace: params.namespace } });
199
+ }
200
+ throw e;
201
+ }
162
202
  });
163
203
  }
164
204
  updateSecret(params) {
@@ -226,7 +266,24 @@ export class KomputerClient {
226
266
  }
227
267
  // --- WebSocket ---
228
268
  watchAgent(name) {
229
- const wsUrl = this._baseUrl.replace("http://", "ws://").replace("https://", "wss://");
230
- return new AgentEventStream(wsUrl, name);
269
+ return __awaiter(this, void 0, void 0, function* () {
270
+ const wsUrl = this._baseUrl.replace("http://", "ws://").replace("https://", "wss://");
271
+ let history = [];
272
+ try {
273
+ const resp = yield this._agents.getAgentEvents({ name, limit: 200 });
274
+ if (resp && Array.isArray(resp.events)) {
275
+ history = resp.events.map((e) => ({
276
+ agentName: e.agentName || name,
277
+ type: e.type || "",
278
+ timestamp: e.timestamp || "",
279
+ payload: e.payload || {},
280
+ }));
281
+ }
282
+ }
283
+ catch (_a) {
284
+ // History fetch failed — proceed with live-only.
285
+ }
286
+ return new AgentEventStream(wsUrl, name, history);
287
+ });
231
288
  }
232
289
  }
@@ -9,6 +9,8 @@ export interface AgentEvent {
9
9
  }
10
10
  /**
11
11
  * Async iterable stream of agent events over WebSocket.
12
+ * Yields pre-fetched history events first, then live WebSocket events,
13
+ * deduplicating by timestamp+type.
12
14
  *
13
15
  * @example
14
16
  * for await (const event of client.watchAgent("my-agent")) {
@@ -22,7 +24,9 @@ export declare class AgentEventStream implements AsyncIterable<AgentEvent> {
22
24
  private queue;
23
25
  private resolve;
24
26
  private done;
25
- constructor(wsUrl: string, agentName: string);
27
+ private seen;
28
+ constructor(wsUrl: string, agentName: string, historyEvents?: AgentEvent[]);
29
+ private dedupKey;
26
30
  [Symbol.asyncIterator](): AsyncIterator<AgentEvent>;
27
31
  close(): void;
28
32
  }
package/dist/esm/watch.js CHANGED
@@ -3,6 +3,8 @@
3
3
  */
4
4
  /**
5
5
  * Async iterable stream of agent events over WebSocket.
6
+ * Yields pre-fetched history events first, then live WebSocket events,
7
+ * deduplicating by timestamp+type.
6
8
  *
7
9
  * @example
8
10
  * for await (const event of client.watchAgent("my-agent")) {
@@ -11,11 +13,20 @@
11
13
  * }
12
14
  */
13
15
  export class AgentEventStream {
14
- constructor(wsUrl, agentName) {
16
+ constructor(wsUrl, agentName, historyEvents) {
15
17
  this.queue = [];
16
18
  this.resolve = null;
17
19
  this.done = false;
20
+ this.seen = new Set();
18
21
  this.agentName = agentName;
22
+ // Seed dedup set and queue with history events.
23
+ if (historyEvents) {
24
+ for (const e of historyEvents) {
25
+ const key = this.dedupKey(e);
26
+ this.seen.add(key);
27
+ this.queue.push(e);
28
+ }
29
+ }
19
30
  this.ws = new WebSocket(`${wsUrl}/api/v1/agents/${agentName}/ws`);
20
31
  this.ws.onmessage = (event) => {
21
32
  const data = JSON.parse(event.data);
@@ -25,6 +36,10 @@ export class AgentEventStream {
25
36
  timestamp: data.timestamp || "",
26
37
  payload: data.payload || {},
27
38
  };
39
+ const key = this.dedupKey(agentEvent);
40
+ if (this.seen.has(key))
41
+ return;
42
+ this.seen.add(key);
28
43
  if (this.resolve) {
29
44
  const r = this.resolve;
30
45
  this.resolve = null;
@@ -51,6 +66,10 @@ export class AgentEventStream {
51
66
  }
52
67
  };
53
68
  }
69
+ dedupKey(e) {
70
+ const normType = e.type === "task_started" ? "user_message" : e.type;
71
+ return `${e.timestamp}:${normType}`;
72
+ }
54
73
  [Symbol.asyncIterator]() {
55
74
  return {
56
75
  next: () => {
package/dist/watch.d.ts CHANGED
@@ -9,6 +9,8 @@ export interface AgentEvent {
9
9
  }
10
10
  /**
11
11
  * Async iterable stream of agent events over WebSocket.
12
+ * Yields pre-fetched history events first, then live WebSocket events,
13
+ * deduplicating by timestamp+type.
12
14
  *
13
15
  * @example
14
16
  * for await (const event of client.watchAgent("my-agent")) {
@@ -22,7 +24,9 @@ export declare class AgentEventStream implements AsyncIterable<AgentEvent> {
22
24
  private queue;
23
25
  private resolve;
24
26
  private done;
25
- constructor(wsUrl: string, agentName: string);
27
+ private seen;
28
+ constructor(wsUrl: string, agentName: string, historyEvents?: AgentEvent[]);
29
+ private dedupKey;
26
30
  [Symbol.asyncIterator](): AsyncIterator<AgentEvent>;
27
31
  close(): void;
28
32
  }
package/dist/watch.js CHANGED
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.AgentEventStream = void 0;
7
7
  /**
8
8
  * Async iterable stream of agent events over WebSocket.
9
+ * Yields pre-fetched history events first, then live WebSocket events,
10
+ * deduplicating by timestamp+type.
9
11
  *
10
12
  * @example
11
13
  * for await (const event of client.watchAgent("my-agent")) {
@@ -14,11 +16,20 @@ exports.AgentEventStream = void 0;
14
16
  * }
15
17
  */
16
18
  class AgentEventStream {
17
- constructor(wsUrl, agentName) {
19
+ constructor(wsUrl, agentName, historyEvents) {
18
20
  this.queue = [];
19
21
  this.resolve = null;
20
22
  this.done = false;
23
+ this.seen = new Set();
21
24
  this.agentName = agentName;
25
+ // Seed dedup set and queue with history events.
26
+ if (historyEvents) {
27
+ for (const e of historyEvents) {
28
+ const key = this.dedupKey(e);
29
+ this.seen.add(key);
30
+ this.queue.push(e);
31
+ }
32
+ }
22
33
  this.ws = new WebSocket(`${wsUrl}/api/v1/agents/${agentName}/ws`);
23
34
  this.ws.onmessage = (event) => {
24
35
  const data = JSON.parse(event.data);
@@ -28,6 +39,10 @@ class AgentEventStream {
28
39
  timestamp: data.timestamp || "",
29
40
  payload: data.payload || {},
30
41
  };
42
+ const key = this.dedupKey(agentEvent);
43
+ if (this.seen.has(key))
44
+ return;
45
+ this.seen.add(key);
31
46
  if (this.resolve) {
32
47
  const r = this.resolve;
33
48
  this.resolve = null;
@@ -54,6 +69,10 @@ class AgentEventStream {
54
69
  }
55
70
  };
56
71
  }
72
+ dedupKey(e) {
73
+ const normType = e.type === "task_started" ? "user_message" : e.type;
74
+ return `${e.timestamp}:${normType}`;
75
+ }
57
76
  [Symbol.asyncIterator]() {
58
77
  return {
59
78
  next: () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@komputer-ai/sdk",
3
- "version": "0.11.2",
3
+ "version": "0.11.5",
4
4
  "description": "TypeScript SDK for the komputer.ai platform",
5
5
  "author": "kontroloop-ai",
6
6
  "license": "MIT",
@@ -17,10 +17,14 @@
17
17
  "module": "./dist/esm/index.js",
18
18
  "sideEffects": false,
19
19
  "scripts": {
20
- "build": "tsc && tsc -p tsconfig.esm.json"
20
+ "build": "tsc && tsc -p tsconfig.esm.json",
21
+ "test": "vitest run src/client.test.ts",
22
+ "test:integration": "vitest run src/integration.test.ts"
21
23
  },
22
24
  "devDependencies": {
25
+ "@types/ws": "^8.18.1",
23
26
  "typescript": "^4.0 || ^5.0",
24
- "vitest": "^4.1.4"
27
+ "vitest": "^4.1.4",
28
+ "ws": "^8.20.0"
25
29
  }
26
30
  }