@poncho-ai/harness 0.37.1 → 0.38.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @poncho-ai/harness@0.37.1 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
2
+ > @poncho-ai/harness@0.38.0 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
3
3
  > node scripts/embed-docs.js && tsup src/index.ts --format esm --dts
4
4
 
5
5
  [embed-docs] Generated poncho-docs.ts with 4 topics
@@ -8,9 +8,9 @@
8
8
  CLI tsup v8.5.1
9
9
  CLI Target: es2022
10
10
  ESM Build start
11
- ESM dist/index.js 389.90 KB
11
+ ESM dist/index.js 402.58 KB
12
12
  ESM dist/isolate-TCWTUVG4.js 47.34 KB
13
- ESM ⚡️ Build success in 211ms
13
+ ESM ⚡️ Build success in 197ms
14
14
  DTS Build start
15
- DTS ⚡️ Build success in 6845ms
16
- DTS dist/index.d.ts 56.62 KB
15
+ DTS ⚡️ Build success in 7534ms
16
+ DTS dist/index.d.ts 58.26 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # @poncho-ai/harness
2
2
 
3
+ ## 0.38.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`620a0c8`](https://github.com/cesr/poncho-ai/commit/620a0c89efaafce28968fca5cbde2e2b19bd1595) Thanks [@cesr](https://github.com/cesr)! - feat: add recurrent reminders (daily, weekly, monthly, cron)
8
+
9
+ The `set_reminder` tool now accepts an optional `recurrence` parameter that makes reminders repeat on a schedule instead of firing once. Supports daily, weekly (with specific days-of-week), monthly, and cron expressions. Recurring reminders are rescheduled after each firing and can be bounded by `maxOccurrences` or `endsAt`. Cancel a recurring reminder to stop all future occurrences.
10
+
11
+ ### Patch Changes
12
+
13
+ - [`6486de2`](https://github.com/cesr/poncho-ai/commit/6486de2242a2976068e4bd09f7c0f2d978c35c96) Thanks [@cesr](https://github.com/cesr)! - fix: persist subagent `parentConversationId` atomically so children never appear top-level in the sidebar.
14
+
15
+ `SubagentManager.spawn` previously did a two-step write: `conversationStore.create(...)` followed by `conversationStore.update(...)` to attach `parentConversationId`, `subagentMeta`, and the initial user message. If the follow-up update was interrupted (serverless timeout, transient DB error), the child row was left in the database with `parent_conversation_id = NULL`, so it slipped past the `!c.parentConversationId` filter on `/api/conversations` and showed up as a top-level conversation. This was especially visible with cron-driven research subagents.
16
+
17
+ `ConversationStore.create` now accepts an optional `init` bag (`parentConversationId`, `subagentMeta`, `messages`, `channelMeta`) that is written in the single INSERT — both into the `data` blob and into the dedicated `parent_conversation_id` column. `spawn` passes those fields through and drops the redundant update, eliminating the orphan window. All existing `create(ownerId, title, tenantId)` callers keep working since `init` is optional.
18
+
19
+ - [`0d0578f`](https://github.com/cesr/poncho-ai/commit/0d0578fbc97a3d2644c4e22cab14ff02a79f805f) Thanks [@cesr](https://github.com/cesr)! - fix: route file tools through MountableFs so `/project/` paths resolve correctly
20
+
21
+ `edit_file`, `read_file`, and `write_file` were hitting `engine.vfs` directly, which has no knowledge of the `/project/` mount that bash uses via `MountableFs`. This caused `edit_file` to throw "File not found" on `/project/` paths that bash could see fine. All three file tools now receive a filesystem factory from `BashEnvironmentManager.getFs()` that returns the same combined filesystem (VFS + `/project/` overlay) that bash uses.
22
+
23
+ ## 0.37.2
24
+
25
+ ### Patch Changes
26
+
27
+ - [`2229f74`](https://github.com/cesr/poncho-ai/commit/2229f74ae4d02c5618c60787a7db925060cc1313) Thanks [@cesr](https://github.com/cesr)! - fix: stop invalidating the prompt cache across runs and preserve cache reads when tool results are in flight.
28
+
29
+ Two issues were degrading prompt-cache hit rates to ~0 between turns:
30
+ 1. The system prompt embedded `new Date().toISOString()` (millisecond precision) on every run when a reminder store was active, which changed the very first block of the prefix and prevented any cross-run cache match. The timestamp is now quantized to the hour, which keeps the system prompt stable across runs while still giving the agent a usable sense of time.
31
+ 2. When the message history contained untruncated tool results from the previous run, prompt caching was disabled entirely — no `cache_control` breakpoint was emitted, which also killed cache _reads_ of the stable prefix (system prompt + earlier turns). The breakpoint is now placed immediately before the first untruncated tool result instead, so the stable prefix is still cached and read while the soon-to-be-truncated tail stays out of the cache.
32
+
33
+ `addPromptCacheBreakpoints` now takes an optional `targetIndex` to support this.
34
+
3
35
  ## 0.37.1
4
36
 
5
37
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -196,11 +196,17 @@ interface Conversation {
196
196
  createdAt: number;
197
197
  updatedAt: number;
198
198
  }
199
+ interface ConversationCreateInit {
200
+ parentConversationId?: string;
201
+ subagentMeta?: Conversation["subagentMeta"];
202
+ messages?: Message[];
203
+ channelMeta?: Conversation["channelMeta"];
204
+ }
199
205
  interface ConversationStore {
200
206
  list(ownerId?: string, tenantId?: string | null): Promise<Conversation[]>;
201
207
  listSummaries(ownerId?: string, tenantId?: string | null): Promise<ConversationSummary[]>;
202
208
  get(conversationId: string): Promise<Conversation | undefined>;
203
- create(ownerId?: string, title?: string, tenantId?: string | null): Promise<Conversation>;
209
+ create(ownerId?: string, title?: string, tenantId?: string | null, init?: ConversationCreateInit): Promise<Conversation>;
204
210
  update(conversation: Conversation): Promise<void>;
205
211
  rename(conversationId: string, title: string): Promise<Conversation | undefined>;
206
212
  delete(conversationId: string): Promise<boolean>;
@@ -234,7 +240,7 @@ declare class InMemoryConversationStore implements ConversationStore {
234
240
  list(ownerId?: string, tenantId?: string | null): Promise<Conversation[]>;
235
241
  listSummaries(ownerId?: string, tenantId?: string | null): Promise<ConversationSummary[]>;
236
242
  get(conversationId: string): Promise<Conversation | undefined>;
237
- create(ownerId?: string, title?: string, tenantId?: string | null): Promise<Conversation>;
243
+ create(ownerId?: string, title?: string, tenantId?: string | null, init?: ConversationCreateInit): Promise<Conversation>;
238
244
  update(conversation: Conversation): Promise<void>;
239
245
  rename(conversationId: string, title: string): Promise<Conversation | undefined>;
240
246
  delete(conversationId: string): Promise<boolean>;
@@ -682,6 +688,20 @@ interface TodoStore {
682
688
  }
683
689
 
684
690
  type ReminderStatus = "pending" | "fired" | "cancelled";
691
+ type RecurrenceType = "daily" | "weekly" | "monthly" | "cron";
692
+ interface Recurrence {
693
+ type: RecurrenceType;
694
+ /** Repeat every N units (e.g. every 2 days). Defaults to 1. */
695
+ interval?: number;
696
+ /** For weekly: which days (0=Sun … 6=Sat). */
697
+ daysOfWeek?: number[];
698
+ /** For type "cron": a 5-field cron expression. */
699
+ expression?: string;
700
+ /** Stop recurring after this epoch-ms timestamp. */
701
+ endsAt?: number;
702
+ /** Stop recurring after this many total firings. */
703
+ maxOccurrences?: number;
704
+ }
685
705
  interface Reminder {
686
706
  id: string;
687
707
  task: string;
@@ -692,20 +712,35 @@ interface Reminder {
692
712
  conversationId: string;
693
713
  ownerId?: string;
694
714
  tenantId?: string | null;
715
+ recurrence?: Recurrence | null;
716
+ occurrenceCount?: number;
717
+ }
718
+ interface ReminderCreateInput {
719
+ task: string;
720
+ scheduledAt: number;
721
+ timezone?: string;
722
+ conversationId: string;
723
+ ownerId?: string;
724
+ tenantId?: string | null;
725
+ recurrence?: Recurrence | null;
695
726
  }
696
727
  interface ReminderStore {
697
728
  list(): Promise<Reminder[]>;
698
- create(input: {
699
- task: string;
700
- scheduledAt: number;
701
- timezone?: string;
702
- conversationId: string;
703
- ownerId?: string;
704
- tenantId?: string | null;
729
+ create(input: ReminderCreateInput): Promise<Reminder>;
730
+ update(id: string, fields: {
731
+ scheduledAt?: number;
732
+ occurrenceCount?: number;
733
+ status?: ReminderStatus;
705
734
  }): Promise<Reminder>;
706
735
  cancel(id: string): Promise<Reminder>;
707
736
  delete(id: string): Promise<void>;
708
737
  }
738
+ /**
739
+ * Given a reminder's current scheduledAt and its recurrence config, compute the
740
+ * next fire time. Returns null if the recurrence is exhausted (maxOccurrences
741
+ * reached or endsAt passed).
742
+ */
743
+ declare const computeNextOccurrence: (reminder: Reminder) => number | null;
709
744
  declare const createReminderStore: (_agentId: string, _config?: StateConfig, _options?: {
710
745
  workingDir?: string;
711
746
  }) => ReminderStore;
@@ -731,7 +766,7 @@ interface StorageEngine {
731
766
  conversations: {
732
767
  list(ownerId?: string, tenantId?: string | null): Promise<ConversationSummary[]>;
733
768
  get(conversationId: string): Promise<Conversation | undefined>;
734
- create(ownerId?: string, title?: string, tenantId?: string | null): Promise<Conversation>;
769
+ create(ownerId?: string, title?: string, tenantId?: string | null, init?: ConversationCreateInit): Promise<Conversation>;
735
770
  update(conversation: Conversation): Promise<void>;
736
771
  rename(conversationId: string, title: string): Promise<Conversation | undefined>;
737
772
  delete(conversationId: string): Promise<boolean>;
@@ -749,13 +784,11 @@ interface StorageEngine {
749
784
  };
750
785
  reminders: {
751
786
  list(tenantId?: string | null): Promise<Reminder[]>;
752
- create(input: {
753
- task: string;
754
- scheduledAt: number;
755
- timezone?: string;
756
- conversationId: string;
757
- ownerId?: string;
758
- tenantId?: string | null;
787
+ create(input: ReminderCreateInput): Promise<Reminder>;
788
+ update(id: string, fields: {
789
+ scheduledAt?: number;
790
+ occurrenceCount?: number;
791
+ status?: ReminderStatus;
759
792
  }): Promise<Reminder>;
760
793
  cancel(id: string): Promise<Reminder>;
761
794
  delete(id: string): Promise<void>;
@@ -1165,7 +1198,7 @@ declare class InMemoryEngine implements StorageEngine {
1165
1198
  conversations: {
1166
1199
  list: (ownerId?: string, tenantId?: string | null) => Promise<ConversationSummary[]>;
1167
1200
  get: (conversationId: string) => Promise<Conversation | undefined>;
1168
- create: (ownerId?: string, title?: string, tenantId?: string | null) => Promise<Conversation>;
1201
+ create: (ownerId?: string, title?: string, tenantId?: string | null, init?: ConversationCreateInit) => Promise<Conversation>;
1169
1202
  update: (conversation: Conversation) => Promise<void>;
1170
1203
  rename: (conversationId: string, title: string) => Promise<Conversation | undefined>;
1171
1204
  delete: (conversationId: string) => Promise<boolean>;
@@ -1183,13 +1216,11 @@ declare class InMemoryEngine implements StorageEngine {
1183
1216
  };
1184
1217
  reminders: {
1185
1218
  list: (tenantId?: string | null) => Promise<Reminder[]>;
1186
- create: (input: {
1187
- task: string;
1188
- scheduledAt: number;
1189
- timezone?: string;
1190
- conversationId: string;
1191
- ownerId?: string;
1192
- tenantId?: string | null;
1219
+ create: (input: ReminderCreateInput) => Promise<Reminder>;
1220
+ update: (id: string, fields: {
1221
+ scheduledAt?: number;
1222
+ occurrenceCount?: number;
1223
+ status?: ReminderStatus;
1193
1224
  }) => Promise<Reminder>;
1194
1225
  cancel: (id: string) => Promise<Reminder>;
1195
1226
  delete: (id: string) => Promise<void>;
@@ -1262,7 +1293,7 @@ declare abstract class SqlStorageEngine implements StorageEngine {
1262
1293
  conversations: {
1263
1294
  list: (ownerId?: string, tenantId?: string | null) => Promise<ConversationSummary[]>;
1264
1295
  get: (conversationId: string) => Promise<Conversation | undefined>;
1265
- create: (ownerId?: string, title?: string, tenantId?: string | null) => Promise<Conversation>;
1296
+ create: (ownerId?: string, title?: string, tenantId?: string | null, init?: ConversationCreateInit) => Promise<Conversation>;
1266
1297
  update: (conversation: Conversation) => Promise<void>;
1267
1298
  rename: (conversationId: string, title: string) => Promise<Conversation | undefined>;
1268
1299
  delete: (conversationId: string) => Promise<boolean>;
@@ -1280,13 +1311,11 @@ declare abstract class SqlStorageEngine implements StorageEngine {
1280
1311
  };
1281
1312
  reminders: {
1282
1313
  list: (tenantId?: string | null) => Promise<Reminder[]>;
1283
- create: (input: {
1284
- task: string;
1285
- scheduledAt: number;
1286
- timezone?: string;
1287
- conversationId: string;
1288
- ownerId?: string;
1289
- tenantId?: string | null;
1314
+ create: (input: ReminderCreateInput) => Promise<Reminder>;
1315
+ update: (id: string, fields: {
1316
+ scheduledAt?: number;
1317
+ occurrenceCount?: number;
1318
+ status?: ReminderStatus;
1290
1319
  }) => Promise<Reminder>;
1291
1320
  cancel: (id: string) => Promise<Reminder>;
1292
1321
  delete: (id: string) => Promise<void>;
@@ -1419,12 +1448,15 @@ declare class BashEnvironmentManager {
1419
1448
  private engine;
1420
1449
  private limits;
1421
1450
  private environments;
1451
+ private filesystems;
1422
1452
  private readonly workingDir;
1423
1453
  private readonly bashOptions;
1424
1454
  constructor(engine: StorageEngine, limits: {
1425
1455
  maxFileSize: number;
1426
1456
  maxTotalStorage: number;
1427
1457
  }, workingDir: string | null, bashConfig?: BashConfig, network?: NetworkConfig);
1458
+ /** Return the combined IFileSystem (VFS + optional /project mount) for a tenant. */
1459
+ getFs(tenantId: string): IFileSystem;
1428
1460
  getOrCreate(tenantId: string): Bash;
1429
1461
  getAdapter(tenantId: string): PonchoFsAdapter;
1430
1462
  /** Refresh the PostgreSQL path cache before a bash.exec() call. */
@@ -1447,4 +1479,4 @@ declare function verifyTenantToken(signingKey: string, token: string): Promise<T
1447
1479
 
1448
1480
  declare const createSubagentTools: (manager: SubagentManager) => ToolDefinition[];
1449
1481
 
1450
- export { type AgentFrontmatter, AgentHarness, type AgentIdentity, type AgentLimitsConfig, type AgentModelConfig, type ArchivedToolResult$1 as ArchivedToolResult, type BashConfig, BashEnvironmentManager, type BashExecutionLimits, type BuiltInToolToggles, type CompactMessagesOptions, type CompactResult, type CompactionConfig, type Conversation, type ConversationState, type ConversationStore, type ConversationSummary, type CronJobConfig, type HarnessOptions, type HarnessRunOutput, InMemoryConversationStore, InMemoryEngine, InMemoryStateStore, type IsolateBinding, type IsolateConfig, LocalMcpBridge, LocalUploadStore, type MainMemory, type McpConfig, type MemoryConfig, type MemoryStore, type MessagingChannelConfig, type ModelProviderFactory, type NetworkConfig, OPENAI_CODEX_CLIENT_ID, type OpenAICodexAuthConfig, type OpenAICodexDeviceAuthRequest, type OpenAICodexSession, type OtlpConfig, type OtlpOption, PONCHO_UPLOAD_SCHEME, type ParsedAgent, type PendingSubagentResult, type PonchoConfig, PonchoFsAdapter, PostgresEngine, type ProviderConfig, type Reminder, type ReminderStatus, type ReminderStore, type RemoteMcpServerConfig, type RuntimeRenderContext, S3UploadStore, STORAGE_SCHEMA_VERSION, type SecretsStore, type SkillContextEntry, type SkillMetadata, SqliteEngine, type StateConfig, type StateProviderName, type StateStore, type StorageConfig, type StorageEngine, type StorageFactoryOptions, type StorageProvider, type SubagentManager, type SubagentResult, type SubagentSpawnResult, type SubagentSummary, type TelemetryConfig, TelemetryEmitter, type TenantTokenPayload, type ToolAccess, type ToolCall, ToolDispatcher, type ToolExecutionResult, type UploadStore, type UploadsConfig, VFS_SCHEME, VercelBlobUploadStore, type VfsDirEntry, type VfsStat, buildAgentDirectoryName, buildSkillContextWindow, compactMessages, completeOpenAICodexDeviceAuth, createBashTool, createConversationStore, createConversationStoreFromEngine, createDefaultTools, createDeleteDirectoryTool, createDeleteTool, createEditTool, createMemoryStore, createMemoryStoreFromEngine, createMemoryTools, createModelProvider, createReminderStore, createReminderStoreFromEngine, createReminderTools, createSearchTools, createSecretsStore, createSkillTools, createStateStore, createStorageEngine, createSubagentTools, createTodoStoreFromEngine, createUploadStore, createWriteTool, deleteOpenAICodexSession, deriveUploadKey, ensureAgentIdentity, estimateTokens, estimateTotalTokens, findSafeSplitPoint, generateAgentId, getAgentStoreDirectory, getModelContextWindow, getOpenAICodexAccessToken, getOpenAICodexAuthFilePath, getOpenAICodexRequiredScopes, getPonchoStoreRoot, jsonSchemaToZod, loadPonchoConfig, loadSkillContext, loadSkillInstructions, loadSkillMetadata, normalizeOtlp, normalizeScriptPolicyPath, parseAgentFile, parseAgentMarkdown, ponchoDocsTool, readOpenAICodexSession, readSkillResource, renderAgentPrompt, resolveAgentIdentity, resolveCompactionConfig, resolveEnv, resolveMemoryConfig, resolveSkillDirs, resolveStateConfig, slugifyStorageComponent, startOpenAICodexDeviceAuth, verifyTenantToken, writeOpenAICodexSession };
1482
+ export { type AgentFrontmatter, AgentHarness, type AgentIdentity, type AgentLimitsConfig, type AgentModelConfig, type ArchivedToolResult$1 as ArchivedToolResult, type BashConfig, BashEnvironmentManager, type BashExecutionLimits, type BuiltInToolToggles, type CompactMessagesOptions, type CompactResult, type CompactionConfig, type Conversation, type ConversationCreateInit, type ConversationState, type ConversationStore, type ConversationSummary, type CronJobConfig, type HarnessOptions, type HarnessRunOutput, InMemoryConversationStore, InMemoryEngine, InMemoryStateStore, type IsolateBinding, type IsolateConfig, LocalMcpBridge, LocalUploadStore, type MainMemory, type McpConfig, type MemoryConfig, type MemoryStore, type MessagingChannelConfig, type ModelProviderFactory, type NetworkConfig, OPENAI_CODEX_CLIENT_ID, type OpenAICodexAuthConfig, type OpenAICodexDeviceAuthRequest, type OpenAICodexSession, type OtlpConfig, type OtlpOption, PONCHO_UPLOAD_SCHEME, type ParsedAgent, type PendingSubagentResult, type PonchoConfig, PonchoFsAdapter, PostgresEngine, type ProviderConfig, type Recurrence, type RecurrenceType, type Reminder, type ReminderCreateInput, type ReminderStatus, type ReminderStore, type RemoteMcpServerConfig, type RuntimeRenderContext, S3UploadStore, STORAGE_SCHEMA_VERSION, type SecretsStore, type SkillContextEntry, type SkillMetadata, SqliteEngine, type StateConfig, type StateProviderName, type StateStore, type StorageConfig, type StorageEngine, type StorageFactoryOptions, type StorageProvider, type SubagentManager, type SubagentResult, type SubagentSpawnResult, type SubagentSummary, type TelemetryConfig, TelemetryEmitter, type TenantTokenPayload, type ToolAccess, type ToolCall, ToolDispatcher, type ToolExecutionResult, type UploadStore, type UploadsConfig, VFS_SCHEME, VercelBlobUploadStore, type VfsDirEntry, type VfsStat, buildAgentDirectoryName, buildSkillContextWindow, compactMessages, completeOpenAICodexDeviceAuth, computeNextOccurrence, createBashTool, createConversationStore, createConversationStoreFromEngine, createDefaultTools, createDeleteDirectoryTool, createDeleteTool, createEditTool, createMemoryStore, createMemoryStoreFromEngine, createMemoryTools, createModelProvider, createReminderStore, createReminderStoreFromEngine, createReminderTools, createSearchTools, createSecretsStore, createSkillTools, createStateStore, createStorageEngine, createSubagentTools, createTodoStoreFromEngine, createUploadStore, createWriteTool, deleteOpenAICodexSession, deriveUploadKey, ensureAgentIdentity, estimateTokens, estimateTotalTokens, findSafeSplitPoint, generateAgentId, getAgentStoreDirectory, getModelContextWindow, getOpenAICodexAccessToken, getOpenAICodexAuthFilePath, getOpenAICodexRequiredScopes, getPonchoStoreRoot, jsonSchemaToZod, loadPonchoConfig, loadSkillContext, loadSkillInstructions, loadSkillMetadata, normalizeOtlp, normalizeScriptPolicyPath, parseAgentFile, parseAgentMarkdown, ponchoDocsTool, readOpenAICodexSession, readSkillResource, renderAgentPrompt, resolveAgentIdentity, resolveCompactionConfig, resolveEnv, resolveMemoryConfig, resolveSkillDirs, resolveStateConfig, slugifyStorageComponent, startOpenAICodexDeviceAuth, verifyTenantToken, writeOpenAICodexSession };