@poncho-ai/harness 0.16.1 → 0.18.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/dist/index.js CHANGED
@@ -466,7 +466,7 @@ var createWriteTool = (workingDir) => defineTool({
466
466
 
467
467
  // src/harness.ts
468
468
  import { randomUUID as randomUUID3 } from "crypto";
469
- import { getTextContent } from "@poncho-ai/sdk";
469
+ import { getTextContent as getTextContent2 } from "@poncho-ai/sdk";
470
470
 
471
471
  // src/upload-store.ts
472
472
  import { createHash as createHash2 } from "crypto";
@@ -1306,16 +1306,19 @@ var StreamableHttpMcpRpcClient = class {
1306
1306
  endpoint;
1307
1307
  timeoutMs;
1308
1308
  bearerToken;
1309
+ customHeaders;
1309
1310
  idCounter = 1;
1310
1311
  initialized = false;
1311
1312
  sessionId;
1312
- constructor(endpoint, timeoutMs = 1e4, bearerToken) {
1313
+ constructor(endpoint, timeoutMs = 1e4, bearerToken, customHeaders) {
1313
1314
  this.endpoint = endpoint;
1314
1315
  this.timeoutMs = timeoutMs;
1315
1316
  this.bearerToken = bearerToken;
1317
+ this.customHeaders = customHeaders ?? {};
1316
1318
  }
1317
1319
  buildHeaders(accept) {
1318
1320
  const headers = {
1321
+ ...this.customHeaders,
1319
1322
  "Content-Type": "application/json",
1320
1323
  Accept: accept
1321
1324
  };
@@ -1596,7 +1599,8 @@ var LocalMcpBridge = class {
1596
1599
  new StreamableHttpMcpRpcClient(
1597
1600
  server.url,
1598
1601
  server.timeoutMs ?? 1e4,
1599
- server.auth?.tokenEnv ? process.env[server.auth.tokenEnv] : void 0
1602
+ server.auth?.tokenEnv ? process.env[server.auth.tokenEnv] : void 0,
1603
+ server.headers
1600
1604
  )
1601
1605
  );
1602
1606
  }
@@ -2447,6 +2451,138 @@ var extractRunnableFunction = (value) => {
2447
2451
  return void 0;
2448
2452
  };
2449
2453
 
2454
+ // src/subagent-tools.ts
2455
+ import { defineTool as defineTool4, getTextContent } from "@poncho-ai/sdk";
2456
+ var LAST_MESSAGES_TO_RETURN = 10;
2457
+ var summarizeResult = (r) => {
2458
+ const summary = {
2459
+ subagentId: r.subagentId,
2460
+ status: r.status
2461
+ };
2462
+ if (r.result) {
2463
+ summary.result = {
2464
+ status: r.result.status,
2465
+ response: r.result.response,
2466
+ steps: r.result.steps,
2467
+ duration: r.result.duration
2468
+ };
2469
+ }
2470
+ if (r.error) {
2471
+ summary.error = r.error;
2472
+ }
2473
+ if (r.latestMessages && r.latestMessages.length > 0) {
2474
+ summary.latestMessages = r.latestMessages.slice(-LAST_MESSAGES_TO_RETURN).map((m) => ({
2475
+ role: m.role,
2476
+ content: getTextContent(m).slice(0, 2e3)
2477
+ }));
2478
+ }
2479
+ return summary;
2480
+ };
2481
+ var createSubagentTools = (manager, getConversationId, getOwnerId) => [
2482
+ defineTool4({
2483
+ name: "spawn_subagent",
2484
+ description: "Spawn a subagent to work on a task and wait for it to finish. The subagent is a full copy of yourself running in its own conversation context with access to the same tools (except memory writes). This call blocks until the subagent completes and returns its result.\n\nGuidelines:\n- Use subagents to parallelize work: call spawn_subagent multiple times in one response for independent sub-tasks -- they run concurrently.\n- Prefer doing work yourself for simple or quick tasks. Spawn subagents for substantial, self-contained work.\n- The subagent has no memory of your conversation -- write thorough, self-contained instructions in the task.",
2485
+ inputSchema: {
2486
+ type: "object",
2487
+ properties: {
2488
+ task: {
2489
+ type: "string",
2490
+ description: "Thorough, self-contained instructions for the subagent. Include all relevant context, goals, and constraints -- the subagent starts with zero prior conversation history."
2491
+ }
2492
+ },
2493
+ required: ["task"],
2494
+ additionalProperties: false
2495
+ },
2496
+ handler: async (input) => {
2497
+ const task = typeof input.task === "string" ? input.task : "";
2498
+ if (!task.trim()) {
2499
+ return { error: "task is required" };
2500
+ }
2501
+ const conversationId = getConversationId();
2502
+ if (!conversationId) {
2503
+ return { error: "no active conversation to spawn subagent from" };
2504
+ }
2505
+ const result = await manager.spawn({
2506
+ task: task.trim(),
2507
+ parentConversationId: conversationId,
2508
+ ownerId: getOwnerId()
2509
+ });
2510
+ return summarizeResult(result);
2511
+ }
2512
+ }),
2513
+ defineTool4({
2514
+ name: "message_subagent",
2515
+ description: "Send a follow-up message to a completed or stopped subagent and wait for it to finish. This restarts the subagent with the new message and blocks until it completes. Only works when the subagent is not currently running.",
2516
+ inputSchema: {
2517
+ type: "object",
2518
+ properties: {
2519
+ subagent_id: {
2520
+ type: "string",
2521
+ description: "The subagent ID (from spawn_subagent result or list_subagents)."
2522
+ },
2523
+ message: {
2524
+ type: "string",
2525
+ description: "The follow-up instructions or message to send."
2526
+ }
2527
+ },
2528
+ required: ["subagent_id", "message"],
2529
+ additionalProperties: false
2530
+ },
2531
+ handler: async (input) => {
2532
+ const subagentId = typeof input.subagent_id === "string" ? input.subagent_id : "";
2533
+ const message = typeof input.message === "string" ? input.message : "";
2534
+ if (!subagentId || !message.trim()) {
2535
+ return { error: "subagent_id and message are required" };
2536
+ }
2537
+ const result = await manager.sendMessage(subagentId, message.trim());
2538
+ return summarizeResult(result);
2539
+ }
2540
+ }),
2541
+ defineTool4({
2542
+ name: "stop_subagent",
2543
+ description: "Stop a running subagent. The subagent's conversation is preserved but it will stop processing. Use this to cancel work that is no longer needed.",
2544
+ inputSchema: {
2545
+ type: "object",
2546
+ properties: {
2547
+ subagent_id: {
2548
+ type: "string",
2549
+ description: "The subagent ID (from spawn_subagent result or list_subagents)."
2550
+ }
2551
+ },
2552
+ required: ["subagent_id"],
2553
+ additionalProperties: false
2554
+ },
2555
+ handler: async (input) => {
2556
+ const subagentId = typeof input.subagent_id === "string" ? input.subagent_id : "";
2557
+ if (!subagentId) {
2558
+ return { error: "subagent_id is required" };
2559
+ }
2560
+ await manager.stop(subagentId);
2561
+ return { message: `Subagent "${subagentId}" has been stopped.` };
2562
+ }
2563
+ }),
2564
+ defineTool4({
2565
+ name: "list_subagents",
2566
+ description: "List all subagents that have been spawned in this conversation. Returns each subagent's ID, original task, current status, and message count. Use this to look up subagent IDs before calling message_subagent or stop_subagent.",
2567
+ inputSchema: {
2568
+ type: "object",
2569
+ properties: {},
2570
+ additionalProperties: false
2571
+ },
2572
+ handler: async () => {
2573
+ const conversationId = getConversationId();
2574
+ if (!conversationId) {
2575
+ return { error: "no active conversation" };
2576
+ }
2577
+ const subagents = await manager.list(conversationId);
2578
+ if (subagents.length === 0) {
2579
+ return { message: "No subagents have been spawned in this conversation." };
2580
+ }
2581
+ return { subagents };
2582
+ }
2583
+ })
2584
+ ];
2585
+
2450
2586
  // src/harness.ts
2451
2587
  import { LatitudeTelemetry } from "@latitude-data/telemetry";
2452
2588
  import { diag, DiagLogLevel } from "@opentelemetry/api";
@@ -2928,6 +3064,7 @@ var AgentHarness = class {
2928
3064
  _browserMod;
2929
3065
  parsedAgent;
2930
3066
  mcpBridge;
3067
+ subagentManager;
2931
3068
  resolveToolAccess(toolName) {
2932
3069
  const tools = this.loadedConfig?.tools;
2933
3070
  if (!tools) return true;
@@ -2964,6 +3101,19 @@ var AgentHarness = class {
2964
3101
  this.dispatcher.register(tool);
2965
3102
  }
2966
3103
  }
3104
+ unregisterTools(names) {
3105
+ this.dispatcher.unregisterMany(names);
3106
+ }
3107
+ setSubagentManager(manager) {
3108
+ this.subagentManager = manager;
3109
+ this.dispatcher.registerMany(
3110
+ createSubagentTools(
3111
+ manager,
3112
+ () => this._currentRunConversationId,
3113
+ () => this._currentRunOwnerId ?? "anonymous"
3114
+ )
3115
+ );
3116
+ }
2967
3117
  registerConfiguredBuiltInTools(config) {
2968
3118
  for (const tool of createDefaultTools(this.workingDir)) {
2969
3119
  if (this.isToolEnabled(tool.name)) {
@@ -3418,6 +3568,8 @@ var AgentHarness = class {
3418
3568
  }
3419
3569
  /** Conversation ID of the currently executing run (set during run, cleared after). */
3420
3570
  _currentRunConversationId;
3571
+ /** Owner ID of the currently executing run (used by subagent tools). */
3572
+ _currentRunOwnerId;
3421
3573
  get browserSession() {
3422
3574
  return this._browserSession;
3423
3575
  }
@@ -3515,6 +3667,10 @@ var AgentHarness = class {
3515
3667
  }
3516
3668
  await this.refreshSkillsIfChanged();
3517
3669
  this._currentRunConversationId = input.conversationId;
3670
+ const ownerParam = input.parameters?.__ownerId;
3671
+ if (typeof ownerParam === "string") {
3672
+ this._currentRunOwnerId = ownerParam;
3673
+ }
3518
3674
  const agent = this.parsedAgent;
3519
3675
  const runId = `run_${randomUUID3()}`;
3520
3676
  const start = now();
@@ -3715,7 +3871,7 @@ ${boundedMainMemory.trim()}` : "";
3715
3871
  if (rich && rich.length > 0) {
3716
3872
  return [{ role: "tool", content: rich }];
3717
3873
  }
3718
- const textContent = typeof msg.content === "string" ? msg.content : getTextContent(msg);
3874
+ const textContent = typeof msg.content === "string" ? msg.content : getTextContent2(msg);
3719
3875
  try {
3720
3876
  const parsed = JSON.parse(textContent);
3721
3877
  if (!Array.isArray(parsed)) {
@@ -3765,7 +3921,7 @@ ${boundedMainMemory.trim()}` : "";
3765
3921
  }
3766
3922
  }
3767
3923
  if (msg.role === "assistant") {
3768
- const assistantText = typeof msg.content === "string" ? msg.content : getTextContent(msg);
3924
+ const assistantText = typeof msg.content === "string" ? msg.content : getTextContent2(msg);
3769
3925
  try {
3770
3926
  const parsed = JSON.parse(assistantText);
3771
3927
  if (typeof parsed === "object" && parsed !== null) {
@@ -3804,7 +3960,7 @@ ${boundedMainMemory.trim()}` : "";
3804
3960
  if (msg.role === "system") {
3805
3961
  return [{
3806
3962
  role: "system",
3807
- content: typeof msg.content === "string" ? msg.content : getTextContent(msg)
3963
+ content: typeof msg.content === "string" ? msg.content : getTextContent2(msg)
3808
3964
  }];
3809
3965
  }
3810
3966
  if (msg.role === "user") {
@@ -3911,7 +4067,7 @@ ${textContent}` };
3911
4067
  let chunkCount = 0;
3912
4068
  const hasRunTimeout = timeoutMs > 0;
3913
4069
  const streamDeadline = hasRunTimeout ? start + timeoutMs : 0;
3914
- const textIterator = result.textStream[Symbol.asyncIterator]();
4070
+ const fullStreamIterator = result.fullStream[Symbol.asyncIterator]();
3915
4071
  try {
3916
4072
  while (true) {
3917
4073
  if (isCancelled()) {
@@ -3937,20 +4093,20 @@ ${textContent}` };
3937
4093
  }
3938
4094
  const remaining = hasRunTimeout ? streamDeadline - now() : Infinity;
3939
4095
  const timeout = chunkCount === 0 ? Math.min(remaining, FIRST_CHUNK_TIMEOUT_MS) : hasRunTimeout ? remaining : 0;
3940
- let nextChunk;
4096
+ let nextPart;
3941
4097
  if (timeout <= 0 && chunkCount > 0) {
3942
- nextChunk = await textIterator.next();
4098
+ nextPart = await fullStreamIterator.next();
3943
4099
  } else {
3944
4100
  let timer;
3945
- nextChunk = await Promise.race([
3946
- textIterator.next(),
4101
+ nextPart = await Promise.race([
4102
+ fullStreamIterator.next(),
3947
4103
  new Promise((resolve10) => {
3948
4104
  timer = setTimeout(() => resolve10(null), timeout);
3949
4105
  })
3950
4106
  ]);
3951
4107
  clearTimeout(timer);
3952
4108
  }
3953
- if (nextChunk === null) {
4109
+ if (nextPart === null) {
3954
4110
  const isFirstChunk = chunkCount === 0;
3955
4111
  console.error(
3956
4112
  `[poncho][harness] Stream timeout waiting for ${isFirstChunk ? "first" : "next"} chunk: model="${modelName}", step=${step}, chunks=${chunkCount}, elapsed=${now() - start}ms`
@@ -3968,13 +4124,19 @@ ${textContent}` };
3968
4124
  });
3969
4125
  return;
3970
4126
  }
3971
- if (nextChunk.done) break;
3972
- chunkCount += 1;
3973
- fullText += nextChunk.value;
3974
- yield pushEvent({ type: "model:chunk", content: nextChunk.value });
4127
+ if (nextPart.done) break;
4128
+ const part = nextPart.value;
4129
+ if (part.type === "text-delta") {
4130
+ chunkCount += 1;
4131
+ fullText += part.text;
4132
+ yield pushEvent({ type: "model:chunk", content: part.text });
4133
+ } else if (part.type === "tool-input-start") {
4134
+ chunkCount += 1;
4135
+ yield pushEvent({ type: "tool:generating", tool: part.toolName, toolCallId: part.id });
4136
+ }
3975
4137
  }
3976
4138
  } finally {
3977
- textIterator.return?.(void 0)?.catch?.(() => {
4139
+ fullStreamIterator.return?.(void 0)?.catch?.(() => {
3978
4140
  });
3979
4141
  }
3980
4142
  if (isCancelled()) {
@@ -4074,7 +4236,8 @@ ${textContent}` };
4074
4236
  step,
4075
4237
  workingDir: this.workingDir,
4076
4238
  parameters: input.parameters ?? {},
4077
- abortSignal: input.abortSignal
4239
+ abortSignal: input.abortSignal,
4240
+ conversationId: input.conversationId
4078
4241
  };
4079
4242
  const toolResultsForModel = [];
4080
4243
  const richToolResults = [];
@@ -4179,11 +4342,14 @@ ${textContent}` };
4179
4342
  });
4180
4343
  } else {
4181
4344
  span?.end({ result: { value: result2.output ?? null, isError: false } });
4345
+ const serialized = JSON.stringify(result2.output ?? null);
4346
+ const outputTokenEstimate = Math.ceil(serialized.length / 4);
4182
4347
  yield pushEvent({
4183
4348
  type: "tool:completed",
4184
4349
  tool: result2.tool,
4185
4350
  output: result2.output,
4186
- duration: now() - batchStart
4351
+ duration: now() - batchStart,
4352
+ outputTokenEstimate
4187
4353
  });
4188
4354
  const { mediaItems, strippedOutput } = extractMediaFromToolOutput(result2.output);
4189
4355
  toolResultsForModel.push({
@@ -4537,9 +4703,22 @@ var InMemoryConversationStore = class {
4537
4703
  }
4538
4704
  }
4539
4705
  }
4540
- async list(ownerId = DEFAULT_OWNER) {
4706
+ async list(ownerId) {
4541
4707
  this.purgeExpired();
4542
- return Array.from(this.conversations.values()).filter((conversation) => conversation.ownerId === ownerId).sort((a, b) => b.updatedAt - a.updatedAt);
4708
+ return Array.from(this.conversations.values()).filter((conversation) => !ownerId || conversation.ownerId === ownerId).sort((a, b) => b.updatedAt - a.updatedAt);
4709
+ }
4710
+ async listSummaries(ownerId) {
4711
+ this.purgeExpired();
4712
+ return Array.from(this.conversations.values()).filter((c) => !ownerId || c.ownerId === ownerId).sort((a, b) => b.updatedAt - a.updatedAt).map((c) => ({
4713
+ conversationId: c.conversationId,
4714
+ title: c.title,
4715
+ updatedAt: c.updatedAt,
4716
+ createdAt: c.createdAt,
4717
+ ownerId: c.ownerId,
4718
+ parentConversationId: c.parentConversationId,
4719
+ messageCount: c.messages.length,
4720
+ hasPendingApprovals: Array.isArray(c.pendingApprovals) && c.pendingApprovals.length > 0
4721
+ }));
4543
4722
  }
4544
4723
  async get(conversationId) {
4545
4724
  this.purgeExpired();
@@ -4642,8 +4821,12 @@ var FileConversationStore = class {
4642
4821
  conversationId: conversation.conversationId,
4643
4822
  title: conversation.title,
4644
4823
  updatedAt: conversation.updatedAt,
4824
+ createdAt: conversation.createdAt,
4645
4825
  ownerId: conversation.ownerId,
4646
- fileName: entry.name
4826
+ fileName: entry.name,
4827
+ parentConversationId: conversation.parentConversationId,
4828
+ messageCount: conversation.messages.length,
4829
+ hasPendingApprovals: Array.isArray(conversation.pendingApprovals) && conversation.pendingApprovals.length > 0
4647
4830
  });
4648
4831
  }
4649
4832
  } catch {
@@ -4666,6 +4849,16 @@ var FileConversationStore = class {
4666
4849
  for (const conversation of parsed.conversations ?? []) {
4667
4850
  this.conversations.set(conversation.conversationId, conversation);
4668
4851
  }
4852
+ let needsRebuild = false;
4853
+ for (const entry of this.conversations.values()) {
4854
+ if (entry.messageCount === void 0) {
4855
+ needsRebuild = true;
4856
+ break;
4857
+ }
4858
+ }
4859
+ if (needsRebuild) {
4860
+ await this.rebuildIndexFromFiles();
4861
+ }
4669
4862
  } catch {
4670
4863
  await this.rebuildIndexFromFiles();
4671
4864
  }
@@ -4681,16 +4874,20 @@ var FileConversationStore = class {
4681
4874
  conversationId: conversation.conversationId,
4682
4875
  title: conversation.title,
4683
4876
  updatedAt: conversation.updatedAt,
4877
+ createdAt: conversation.createdAt,
4684
4878
  ownerId: conversation.ownerId,
4685
- fileName
4879
+ fileName,
4880
+ parentConversationId: conversation.parentConversationId,
4881
+ messageCount: conversation.messages.length,
4882
+ hasPendingApprovals: Array.isArray(conversation.pendingApprovals) && conversation.pendingApprovals.length > 0
4686
4883
  });
4687
4884
  await this.writeIndex();
4688
4885
  });
4689
4886
  await this.writing;
4690
4887
  }
4691
- async list(ownerId = DEFAULT_OWNER) {
4888
+ async list(ownerId) {
4692
4889
  await this.ensureLoaded();
4693
- const summaries = Array.from(this.conversations.values()).filter((conversation) => conversation.ownerId === ownerId).sort((a, b) => b.updatedAt - a.updatedAt);
4890
+ const summaries = Array.from(this.conversations.values()).filter((conversation) => !ownerId || conversation.ownerId === ownerId).sort((a, b) => b.updatedAt - a.updatedAt);
4694
4891
  const conversations = [];
4695
4892
  for (const summary of summaries) {
4696
4893
  const loaded = await this.readConversationFile(summary.fileName);
@@ -4700,6 +4897,19 @@ var FileConversationStore = class {
4700
4897
  }
4701
4898
  return conversations;
4702
4899
  }
4900
+ async listSummaries(ownerId) {
4901
+ await this.ensureLoaded();
4902
+ return Array.from(this.conversations.values()).filter((c) => !ownerId || c.ownerId === ownerId).sort((a, b) => b.updatedAt - a.updatedAt).map((c) => ({
4903
+ conversationId: c.conversationId,
4904
+ title: c.title,
4905
+ updatedAt: c.updatedAt,
4906
+ createdAt: c.createdAt,
4907
+ ownerId: c.ownerId,
4908
+ parentConversationId: c.parentConversationId,
4909
+ messageCount: c.messageCount,
4910
+ hasPendingApprovals: c.hasPendingApprovals
4911
+ }));
4912
+ }
4703
4913
  async get(conversationId) {
4704
4914
  await this.ensureLoaded();
4705
4915
  const summary = this.conversations.get(conversationId);
@@ -4915,11 +5125,14 @@ var KeyValueConversationStoreBase = class {
4915
5125
  return void 0;
4916
5126
  }
4917
5127
  }
4918
- async list(ownerId = DEFAULT_OWNER) {
5128
+ async list(ownerId) {
4919
5129
  const kv = await this.client();
4920
5130
  if (!kv) {
4921
5131
  return await this.memoryFallback.list(ownerId);
4922
5132
  }
5133
+ if (!ownerId) {
5134
+ return [];
5135
+ }
4923
5136
  const ids = await this.getOwnerConversationIds(ownerId);
4924
5137
  const conversations = [];
4925
5138
  for (const id of ids) {
@@ -4934,6 +5147,33 @@ var KeyValueConversationStoreBase = class {
4934
5147
  }
4935
5148
  return conversations.sort((a, b) => b.updatedAt - a.updatedAt);
4936
5149
  }
5150
+ async listSummaries(ownerId) {
5151
+ const kv = await this.client();
5152
+ if (!kv) {
5153
+ return await this.memoryFallback.listSummaries(ownerId);
5154
+ }
5155
+ if (!ownerId) {
5156
+ return [];
5157
+ }
5158
+ const ids = await this.getOwnerConversationIds(ownerId);
5159
+ const summaries = [];
5160
+ for (const id of ids) {
5161
+ const meta = await this.getConversationMeta(id);
5162
+ if (meta && meta.ownerId === ownerId) {
5163
+ summaries.push({
5164
+ conversationId: meta.conversationId,
5165
+ title: meta.title,
5166
+ updatedAt: meta.updatedAt,
5167
+ createdAt: meta.createdAt,
5168
+ ownerId: meta.ownerId,
5169
+ parentConversationId: meta.parentConversationId,
5170
+ messageCount: meta.messageCount,
5171
+ hasPendingApprovals: meta.hasPendingApprovals
5172
+ });
5173
+ }
5174
+ }
5175
+ return summaries.sort((a, b) => b.updatedAt - a.updatedAt);
5176
+ }
4937
5177
  async get(conversationId) {
4938
5178
  const kv = await this.client();
4939
5179
  if (!kv) {
@@ -4983,7 +5223,11 @@ var KeyValueConversationStoreBase = class {
4983
5223
  conversationId: nextConversation.conversationId,
4984
5224
  title: nextConversation.title,
4985
5225
  updatedAt: nextConversation.updatedAt,
4986
- ownerId: nextConversation.ownerId
5226
+ createdAt: nextConversation.createdAt,
5227
+ ownerId: nextConversation.ownerId,
5228
+ parentConversationId: nextConversation.parentConversationId,
5229
+ messageCount: nextConversation.messages.length,
5230
+ hasPendingApprovals: Array.isArray(nextConversation.pendingApprovals) && nextConversation.pendingApprovals.length > 0
4987
5231
  }),
4988
5232
  this.ttl
4989
5233
  );
@@ -5449,7 +5693,7 @@ var TelemetryEmitter = class {
5449
5693
  };
5450
5694
 
5451
5695
  // src/index.ts
5452
- import { defineTool as defineTool4 } from "@poncho-ai/sdk";
5696
+ import { defineTool as defineTool5 } from "@poncho-ai/sdk";
5453
5697
  export {
5454
5698
  AgentHarness,
5455
5699
  InMemoryConversationStore,
@@ -5472,9 +5716,10 @@ export {
5472
5716
  createModelProvider,
5473
5717
  createSkillTools,
5474
5718
  createStateStore,
5719
+ createSubagentTools,
5475
5720
  createUploadStore,
5476
5721
  createWriteTool,
5477
- defineTool4 as defineTool,
5722
+ defineTool5 as defineTool,
5478
5723
  deriveUploadKey,
5479
5724
  ensureAgentIdentity,
5480
5725
  generateAgentId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/harness",
3
- "version": "0.16.1",
3
+ "version": "0.18.0",
4
4
  "description": "Agent execution runtime - conversation loop, tool dispatch, streaming",
5
5
  "repository": {
6
6
  "type": "git",
@@ -31,7 +31,7 @@
31
31
  "redis": "^5.10.0",
32
32
  "yaml": "^2.4.0",
33
33
  "zod": "^3.22.0",
34
- "@poncho-ai/sdk": "1.1.1"
34
+ "@poncho-ai/sdk": "1.3.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/mustache": "^4.2.6",