@poncho-ai/harness 0.34.0 → 0.35.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/.turbo/turbo-build.log +11 -11
- package/.turbo/turbo-lint.log +6 -0
- package/.turbo/turbo-test.log +11931 -0
- package/CHANGELOG.md +28 -0
- package/dist/index.d.ts +82 -9
- package/dist/index.js +629 -118
- package/package.json +3 -2
- package/src/compaction.ts +10 -2
- package/src/config.ts +6 -0
- package/src/harness.ts +82 -16
- package/src/index.ts +2 -0
- package/src/mcp.ts +140 -9
- package/src/memory.ts +33 -13
- package/src/reminder-store.ts +6 -0
- package/src/reminder-tools.ts +15 -2
- package/src/secrets-store.ts +252 -0
- package/src/state.ts +41 -19
- package/src/subagent-manager.ts +1 -0
- package/src/subagent-tools.ts +1 -0
- package/src/telemetry.ts +5 -1
- package/src/tenant-token.ts +42 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @poncho-ai/harness
|
|
2
2
|
|
|
3
|
+
## 0.35.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`83d3c5f`](https://github.com/cesr/poncho-ai/commit/83d3c5f841fe84965d1f9fec6dfc5d8832e4489a) Thanks [@cesr](https://github.com/cesr)! - feat: add multi-tenancy with JWT-based tenant scoping
|
|
8
|
+
|
|
9
|
+
Deploy one agent, serve many tenants with fully isolated conversations, memory, reminders, and secrets. Tenancy activates automatically when a valid JWT is received — no config changes needed.
|
|
10
|
+
- **Auth**: `createTenantToken()` in client SDK, `poncho auth create-token` CLI, or any HS256 JWT library.
|
|
11
|
+
- **Isolation**: conversations, memory, reminders, and todos scoped per tenant.
|
|
12
|
+
- **Per-tenant secrets**: encrypted secret overrides for MCP auth tokens, manageable via CLI (`poncho secrets`), API, and web UI settings panel.
|
|
13
|
+
- **MCP**: per-tenant token resolution with deferred discovery for servers without a default env var.
|
|
14
|
+
- **Web UI**: `?token=` tenant access, settings cog for secret management, dark mode support.
|
|
15
|
+
- **Backward compatible**: existing single-user deployments work unchanged.
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Updated dependencies [[`83d3c5f`](https://github.com/cesr/poncho-ai/commit/83d3c5f841fe84965d1f9fec6dfc5d8832e4489a)]:
|
|
20
|
+
- @poncho-ai/sdk@1.8.0
|
|
21
|
+
|
|
22
|
+
## 0.34.1
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- [`59a88cc`](https://github.com/cesr/poncho-ai/commit/59a88cc52b5c3aa7432b820424bb8067174233e5) Thanks [@cesr](https://github.com/cesr)! - fix: improve token estimation accuracy and handle missing attachments
|
|
27
|
+
- Use a JSON-specific token ratio for tool definitions to avoid inflating counts with many MCP tools.
|
|
28
|
+
- Track actual context size from model responses for compaction triggers instead of cumulative input tokens.
|
|
29
|
+
- Gracefully degrade when file attachments are missing or expired instead of crashing.
|
|
30
|
+
|
|
3
31
|
## 0.34.0
|
|
4
32
|
|
|
5
33
|
### Minor Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LanguageModel } from 'ai';
|
|
2
2
|
import * as _poncho_ai_sdk from '@poncho-ai/sdk';
|
|
3
|
-
import { Message, ToolDefinition, RunResult, AgentFailure,
|
|
3
|
+
import { Message, ToolContext, ToolDefinition, RunResult, AgentFailure, RunInput, AgentEvent, JsonSchema } from '@poncho-ai/sdk';
|
|
4
4
|
export { ToolDefinition, defineTool } from '@poncho-ai/sdk';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
|
|
@@ -83,6 +83,11 @@ declare const resolveCompactionConfig: (explicit?: Partial<CompactionConfig>) =>
|
|
|
83
83
|
declare const estimateTokens: (text: string) => number;
|
|
84
84
|
/**
|
|
85
85
|
* Estimate the total token count of a system prompt + messages + tool defs.
|
|
86
|
+
*
|
|
87
|
+
* Tool definitions are structured JSON (property names, braces, enum values)
|
|
88
|
+
* which tokenizes more efficiently than natural language — roughly 5-6
|
|
89
|
+
* chars/token vs ~4 chars/token for prose. We estimate them separately to
|
|
90
|
+
* avoid inflating the count when there are many MCP tools (100+).
|
|
86
91
|
*/
|
|
87
92
|
declare const estimateTotalTokens: (systemPrompt: string, messages: Message[], toolDefinitionsJson?: string) => number;
|
|
88
93
|
/**
|
|
@@ -201,10 +206,16 @@ interface Conversation {
|
|
|
201
206
|
updatedAt: number;
|
|
202
207
|
}
|
|
203
208
|
interface ConversationStore {
|
|
204
|
-
|
|
205
|
-
|
|
209
|
+
/**
|
|
210
|
+
* List conversations. tenantId semantics:
|
|
211
|
+
* undefined = no filter (builder/admin sees everything)
|
|
212
|
+
* null = legacy single-user only
|
|
213
|
+
* string = tenant-scoped
|
|
214
|
+
*/
|
|
215
|
+
list(ownerId?: string, tenantId?: string | null): Promise<Conversation[]>;
|
|
216
|
+
listSummaries(ownerId?: string, tenantId?: string | null): Promise<ConversationSummary[]>;
|
|
206
217
|
get(conversationId: string): Promise<Conversation | undefined>;
|
|
207
|
-
create(ownerId?: string, title?: string): Promise<Conversation>;
|
|
218
|
+
create(ownerId?: string, title?: string, tenantId?: string | null): Promise<Conversation>;
|
|
208
219
|
update(conversation: Conversation): Promise<void>;
|
|
209
220
|
rename(conversationId: string, title: string): Promise<Conversation | undefined>;
|
|
210
221
|
delete(conversationId: string): Promise<boolean>;
|
|
@@ -240,10 +251,10 @@ declare class InMemoryConversationStore implements ConversationStore {
|
|
|
240
251
|
constructor(ttlSeconds?: number);
|
|
241
252
|
private isExpired;
|
|
242
253
|
private purgeExpired;
|
|
243
|
-
list(ownerId?: string): Promise<Conversation[]>;
|
|
244
|
-
listSummaries(ownerId?: string): Promise<ConversationSummary[]>;
|
|
254
|
+
list(ownerId?: string, tenantId?: string | null): Promise<Conversation[]>;
|
|
255
|
+
listSummaries(ownerId?: string, tenantId?: string | null): Promise<ConversationSummary[]>;
|
|
245
256
|
get(conversationId: string): Promise<Conversation | undefined>;
|
|
246
|
-
create(ownerId?: string, title?: string): Promise<Conversation>;
|
|
257
|
+
create(ownerId?: string, title?: string, tenantId?: string | null): Promise<Conversation>;
|
|
247
258
|
update(conversation: Conversation): Promise<void>;
|
|
248
259
|
rename(conversationId: string, title: string): Promise<Conversation | undefined>;
|
|
249
260
|
delete(conversationId: string): Promise<boolean>;
|
|
@@ -256,6 +267,7 @@ type ConversationSummary = {
|
|
|
256
267
|
updatedAt: number;
|
|
257
268
|
createdAt?: number;
|
|
258
269
|
ownerId: string;
|
|
270
|
+
tenantId?: string | null;
|
|
259
271
|
parentConversationId?: string;
|
|
260
272
|
messageCount?: number;
|
|
261
273
|
hasPendingApprovals?: boolean;
|
|
@@ -296,8 +308,9 @@ interface MemoryStore {
|
|
|
296
308
|
}
|
|
297
309
|
declare const createMemoryStore: (agentId: string, config?: MemoryConfig, options?: {
|
|
298
310
|
workingDir?: string;
|
|
311
|
+
tenantId?: string;
|
|
299
312
|
}) => MemoryStore;
|
|
300
|
-
declare const createMemoryTools: (store: MemoryStore, options?: {
|
|
313
|
+
declare const createMemoryTools: (store: MemoryStore | ((context: ToolContext) => MemoryStore), options?: {
|
|
301
314
|
maxRecallConversations?: number;
|
|
302
315
|
}) => ToolDefinition[];
|
|
303
316
|
|
|
@@ -323,10 +336,24 @@ declare class LocalMcpBridge {
|
|
|
323
336
|
private readonly toolCatalog;
|
|
324
337
|
private readonly unavailableServers;
|
|
325
338
|
private readonly authFailedServers;
|
|
339
|
+
private envResolver?;
|
|
340
|
+
/**
|
|
341
|
+
* Set a resolver for per-tenant env vars (e.g. MCP auth tokens).
|
|
342
|
+
* Called by the harness after creating the secrets store.
|
|
343
|
+
*/
|
|
344
|
+
setEnvResolver(resolver: (tenantId: string | undefined, envName: string) => Promise<string | undefined>): void;
|
|
326
345
|
constructor(config: McpConfig | undefined);
|
|
327
346
|
private getServerName;
|
|
328
347
|
private log;
|
|
348
|
+
/** Set of servers where discovery was deferred (no default token, has env resolver). */
|
|
349
|
+
private readonly deferredDiscoveryServers;
|
|
329
350
|
discoverTools(): Promise<void>;
|
|
351
|
+
/**
|
|
352
|
+
* Run deferred discovery and return ToolDefinitions for all newly discovered tools.
|
|
353
|
+
* Call this during run() so the tools are available to the model immediately.
|
|
354
|
+
*/
|
|
355
|
+
discoverAndLoadDeferred(tenantId: string): Promise<ToolDefinition[]>;
|
|
356
|
+
private tryDeferredDiscovery;
|
|
330
357
|
startLocalServers(): Promise<void>;
|
|
331
358
|
stopLocalServers(): Promise<void>;
|
|
332
359
|
listServers(): RemoteMcpServerConfig[];
|
|
@@ -339,6 +366,11 @@ declare class LocalMcpBridge {
|
|
|
339
366
|
toSerializableConfig(): McpConfig;
|
|
340
367
|
getLocalServers(): never[];
|
|
341
368
|
listDiscoveredTools(serverName?: string): string[];
|
|
369
|
+
hasDeferredServers(): boolean;
|
|
370
|
+
/**
|
|
371
|
+
* Return ToolDefinitions for catalog tools not already registered in the dispatcher.
|
|
372
|
+
*/
|
|
373
|
+
getUnregisteredTools(registeredNames: Set<string>): ToolDefinition[];
|
|
342
374
|
loadTools(requestedPatterns: string[]): Promise<ToolDefinition[]>;
|
|
343
375
|
private toToolDefinitions;
|
|
344
376
|
}
|
|
@@ -462,6 +494,12 @@ interface PonchoConfig extends McpConfig {
|
|
|
462
494
|
/** Cron expression controlling how often the reminder poll runs (local and serverless). Default: every 10 minutes. */
|
|
463
495
|
pollSchedule?: string;
|
|
464
496
|
};
|
|
497
|
+
/**
|
|
498
|
+
* Declare env var names that tenants can self-manage via the web UI or API.
|
|
499
|
+
* Key = env var name, value = human-readable label shown in the settings panel.
|
|
500
|
+
* Example: { LINEAR_API_KEY: "Linear API Key", STRIPE_KEY: "Stripe Secret Key" }
|
|
501
|
+
*/
|
|
502
|
+
tenantSecrets?: Record<string, string>;
|
|
465
503
|
/** Set to `false` to disable the built-in web UI (headless / API-only mode). */
|
|
466
504
|
webUi?: false;
|
|
467
505
|
/** Enable browser automation tools. Set `true` for defaults, or provide config. */
|
|
@@ -562,6 +600,7 @@ interface Reminder {
|
|
|
562
600
|
createdAt: number;
|
|
563
601
|
conversationId: string;
|
|
564
602
|
ownerId?: string;
|
|
603
|
+
tenantId?: string | null;
|
|
565
604
|
}
|
|
566
605
|
interface ReminderStore {
|
|
567
606
|
list(): Promise<Reminder[]>;
|
|
@@ -571,6 +610,7 @@ interface ReminderStore {
|
|
|
571
610
|
timezone?: string;
|
|
572
611
|
conversationId: string;
|
|
573
612
|
ownerId?: string;
|
|
613
|
+
tenantId?: string | null;
|
|
574
614
|
}): Promise<Reminder>;
|
|
575
615
|
cancel(id: string): Promise<Reminder>;
|
|
576
616
|
delete(id: string): Promise<void>;
|
|
@@ -579,6 +619,20 @@ declare const createReminderStore: (agentId: string, config?: StateConfig, optio
|
|
|
579
619
|
workingDir?: string;
|
|
580
620
|
}) => ReminderStore;
|
|
581
621
|
|
|
622
|
+
interface SecretsStore {
|
|
623
|
+
get(tenantId: string): Promise<Record<string, string>>;
|
|
624
|
+
set(tenantId: string, key: string, value: string): Promise<void>;
|
|
625
|
+
delete(tenantId: string, key: string): Promise<void>;
|
|
626
|
+
list(tenantId: string): Promise<string[]>;
|
|
627
|
+
}
|
|
628
|
+
declare const createSecretsStore: (agentId: string, signingKey: string, config?: StateConfig, options?: {
|
|
629
|
+
workingDir?: string;
|
|
630
|
+
}) => SecretsStore;
|
|
631
|
+
/**
|
|
632
|
+
* Resolve an env var name: check tenant secrets first, then process.env.
|
|
633
|
+
*/
|
|
634
|
+
declare function resolveEnv(secretsStore: SecretsStore | undefined, tenantId: string | null | undefined, envName: string): Promise<string | undefined>;
|
|
635
|
+
|
|
582
636
|
declare const OPENAI_CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
583
637
|
interface OpenAICodexAuthConfig {
|
|
584
638
|
refreshTokenEnv?: string;
|
|
@@ -655,6 +709,7 @@ interface SubagentManager {
|
|
|
655
709
|
task: string;
|
|
656
710
|
parentConversationId: string;
|
|
657
711
|
ownerId: string;
|
|
712
|
+
tenantId?: string | null;
|
|
658
713
|
}): Promise<SubagentSpawnResult>;
|
|
659
714
|
sendMessage(subagentId: string, message: string): Promise<SubagentSpawnResult>;
|
|
660
715
|
stop(subagentId: string): Promise<void>;
|
|
@@ -715,8 +770,11 @@ declare class AgentHarness {
|
|
|
715
770
|
readonly uploadStore?: UploadStore;
|
|
716
771
|
private skillContextWindow;
|
|
717
772
|
private memoryStore?;
|
|
773
|
+
private readonly tenantMemoryStores;
|
|
774
|
+
private memoryConfig?;
|
|
718
775
|
private todoStore?;
|
|
719
776
|
reminderStore?: ReminderStore;
|
|
777
|
+
secretsStore?: SecretsStore;
|
|
720
778
|
private loadedConfig?;
|
|
721
779
|
private loadedSkills;
|
|
722
780
|
private skillFingerprint;
|
|
@@ -754,6 +812,11 @@ declare class AgentHarness {
|
|
|
754
812
|
private truncateHistoricalToolResults;
|
|
755
813
|
private shouldPreserveSkillToolResult;
|
|
756
814
|
getTodos(conversationId: string): Promise<TodoItem[]>;
|
|
815
|
+
/**
|
|
816
|
+
* Get a memory store, optionally scoped to a tenant.
|
|
817
|
+
* Returns the default (agent-wide) store when tenantId is null/undefined.
|
|
818
|
+
*/
|
|
819
|
+
private getMemoryStore;
|
|
757
820
|
private listActiveSkills;
|
|
758
821
|
private getAgentMcpIntent;
|
|
759
822
|
private getAgentScriptIntent;
|
|
@@ -916,6 +979,16 @@ declare class TelemetryEmitter {
|
|
|
916
979
|
private sendOtlp;
|
|
917
980
|
}
|
|
918
981
|
|
|
982
|
+
interface TenantTokenPayload {
|
|
983
|
+
tenantId: string;
|
|
984
|
+
metadata?: Record<string, unknown>;
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Verify a tenant JWT (HS256) signed with the given key.
|
|
988
|
+
* Returns the decoded payload on success, or undefined on any failure.
|
|
989
|
+
*/
|
|
990
|
+
declare function verifyTenantToken(signingKey: string, token: string): Promise<TenantTokenPayload | undefined>;
|
|
991
|
+
|
|
919
992
|
declare const createSubagentTools: (manager: SubagentManager) => ToolDefinition[];
|
|
920
993
|
|
|
921
|
-
export { type AgentFrontmatter, AgentHarness, type AgentIdentity, type AgentLimitsConfig, type AgentModelConfig, type ArchivedToolResult$1 as ArchivedToolResult, type BuiltInToolToggles, type CompactMessagesOptions, type CompactResult, type CompactionConfig, type Conversation, type ConversationState, type ConversationStore, type ConversationSummary, type CronJobConfig, type HarnessOptions, type HarnessRunOutput, InMemoryConversationStore, InMemoryStateStore, LocalMcpBridge, LocalUploadStore, type MainMemory, type McpConfig, type MemoryConfig, type MemoryStore, type MessagingChannelConfig, type ModelProviderFactory, OPENAI_CODEX_CLIENT_ID, type OpenAICodexAuthConfig, type OpenAICodexDeviceAuthRequest, type OpenAICodexSession, type OtlpConfig, type OtlpOption, PONCHO_UPLOAD_SCHEME, type ParsedAgent, type PendingSubagentResult, type PonchoConfig, type ProviderConfig, type Reminder, type ReminderStatus, type ReminderStore, type RemoteMcpServerConfig, type RuntimeRenderContext, S3UploadStore, STORAGE_SCHEMA_VERSION, type SkillContextEntry, type SkillMetadata, type StateConfig, type StateProviderName, type StateStore, type StorageConfig, type SubagentManager, type SubagentResult, type SubagentSpawnResult, type SubagentSummary, type TelemetryConfig, TelemetryEmitter, type ToolAccess, type ToolCall, ToolDispatcher, type ToolExecutionResult, type UploadStore, type UploadsConfig, VercelBlobUploadStore, buildAgentDirectoryName, buildSkillContextWindow, compactMessages, completeOpenAICodexDeviceAuth, createConversationStore, createDefaultTools, createDeleteDirectoryTool, createDeleteTool, createEditTool, createMemoryStore, createMemoryTools, createModelProvider, createReminderStore, createReminderTools, createSearchTools, createSkillTools, createStateStore, createSubagentTools, 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, resolveMemoryConfig, resolveSkillDirs, resolveStateConfig, slugifyStorageComponent, startOpenAICodexDeviceAuth, writeOpenAICodexSession };
|
|
994
|
+
export { type AgentFrontmatter, AgentHarness, type AgentIdentity, type AgentLimitsConfig, type AgentModelConfig, type ArchivedToolResult$1 as ArchivedToolResult, type BuiltInToolToggles, type CompactMessagesOptions, type CompactResult, type CompactionConfig, type Conversation, type ConversationState, type ConversationStore, type ConversationSummary, type CronJobConfig, type HarnessOptions, type HarnessRunOutput, InMemoryConversationStore, InMemoryStateStore, LocalMcpBridge, LocalUploadStore, type MainMemory, type McpConfig, type MemoryConfig, type MemoryStore, type MessagingChannelConfig, type ModelProviderFactory, OPENAI_CODEX_CLIENT_ID, type OpenAICodexAuthConfig, type OpenAICodexDeviceAuthRequest, type OpenAICodexSession, type OtlpConfig, type OtlpOption, PONCHO_UPLOAD_SCHEME, type ParsedAgent, type PendingSubagentResult, type PonchoConfig, type ProviderConfig, type Reminder, type ReminderStatus, type ReminderStore, type RemoteMcpServerConfig, type RuntimeRenderContext, S3UploadStore, STORAGE_SCHEMA_VERSION, type SecretsStore, type SkillContextEntry, type SkillMetadata, type StateConfig, type StateProviderName, type StateStore, type StorageConfig, type SubagentManager, type SubagentResult, type SubagentSpawnResult, type SubagentSummary, type TelemetryConfig, TelemetryEmitter, type TenantTokenPayload, type ToolAccess, type ToolCall, ToolDispatcher, type ToolExecutionResult, type UploadStore, type UploadsConfig, VercelBlobUploadStore, buildAgentDirectoryName, buildSkillContextWindow, compactMessages, completeOpenAICodexDeviceAuth, createConversationStore, createDefaultTools, createDeleteDirectoryTool, createDeleteTool, createEditTool, createMemoryStore, createMemoryTools, createModelProvider, createReminderStore, createReminderTools, createSearchTools, createSecretsStore, createSkillTools, createStateStore, createSubagentTools, 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 };
|