@vellumai/assistant 0.4.14 → 0.4.15
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/ARCHITECTURE.md +77 -38
- package/README.md +10 -12
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +108 -522
- package/src/__tests__/channel-approval-routes.test.ts +92 -239
- package/src/__tests__/channel-approval.test.ts +100 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +13 -6
- package/src/__tests__/conversation-routes.test.ts +11 -4
- package/src/__tests__/guardian-actions-endpoint.test.ts +26 -19
- package/src/__tests__/mcp-health-check.test.ts +65 -0
- package/src/__tests__/permission-types.test.ts +33 -0
- package/src/__tests__/scan-result-store.test.ts +121 -0
- package/src/__tests__/session-agent-loop.test.ts +120 -0
- package/src/__tests__/session-approval-overrides.test.ts +205 -0
- package/src/__tests__/session-surfaces-task-progress.test.ts +38 -0
- package/src/amazon/client.ts +8 -5
- package/src/approvals/guardian-decision-primitive.ts +14 -9
- package/src/approvals/guardian-request-resolvers.ts +2 -2
- package/src/calls/call-controller.ts +2 -2
- package/src/calls/twilio-routes.ts +2 -2
- package/src/cli/mcp.ts +3 -3
- package/src/cli.ts +24 -0
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +19 -130
- package/src/config/bundled-skills/doordash/__tests__/doordash-client.test.ts +8 -6
- package/src/config/bundled-skills/google-calendar/SKILL.md +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +49 -14
- package/src/config/bundled-skills/messaging/TOOLS.json +52 -9
- package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +35 -11
- package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +3 -1
- package/src/config/bundled-skills/messaging/tools/gmail-forward.ts +5 -6
- package/src/config/bundled-skills/messaging/tools/gmail-outreach-scan.ts +10 -2
- package/src/config/bundled-skills/messaging/tools/gmail-send-draft.ts +20 -0
- package/src/config/bundled-skills/messaging/tools/gmail-send-with-attachments.ts +3 -4
- package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +16 -8
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +76 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +10 -0
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +11 -3
- package/src/config/bundled-skills/messaging/tools/scan-result-store.ts +86 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/skills-catalog/SKILL.md +31 -8
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +68 -24
- package/src/config/bundled-skills/sms-setup/SKILL.md +1 -1
- package/src/config/bundled-skills/telegram-setup/SKILL.md +1 -1
- package/src/config/bundled-skills/twilio-setup/SKILL.md +1 -1
- package/src/daemon/approval-generators.ts +6 -3
- package/src/daemon/handlers/config-ingress.ts +2 -6
- package/src/daemon/handlers/guardian-actions.ts +1 -1
- package/src/daemon/handlers/sessions.ts +4 -1
- package/src/daemon/handlers/shared.ts +3 -0
- package/src/daemon/handlers/skills.ts +32 -0
- package/src/daemon/ipc-contract/messages.ts +3 -1
- package/src/daemon/ipc-handler.ts +24 -0
- package/src/daemon/ipc-validate.ts +1 -1
- package/src/daemon/lifecycle.ts +6 -8
- package/src/daemon/server.ts +8 -3
- package/src/daemon/session-agent-loop.ts +19 -1
- package/src/daemon/session-attachments.ts +2 -1
- package/src/daemon/session-history.ts +2 -2
- package/src/daemon/session-process.ts +5 -9
- package/src/daemon/session-surfaces.ts +17 -1
- package/src/daemon/session-tool-setup.ts +216 -69
- package/src/daemon/session.ts +24 -1
- package/src/events/domain-events.ts +1 -1
- package/src/events/tool-domain-event-publisher.ts +5 -10
- package/src/influencer/client.ts +8 -7
- package/src/messaging/providers/gmail/client.ts +33 -1
- package/src/messaging/providers/gmail/mime-builder.ts +5 -1
- package/src/messaging/providers/sms/adapter.ts +3 -7
- package/src/messaging/providers/telegram-bot/adapter.ts +3 -7
- package/src/messaging/providers/whatsapp/adapter.ts +3 -7
- package/src/notifications/adapters/sms.ts +2 -2
- package/src/notifications/adapters/telegram.ts +2 -2
- package/src/permissions/prompter.ts +2 -0
- package/src/permissions/types.ts +11 -1
- package/src/runtime/approval-conversation-turn.ts +4 -0
- package/src/runtime/auth/__tests__/context.test.ts +130 -0
- package/src/runtime/auth/__tests__/credential-service.test.ts +277 -0
- package/src/runtime/auth/__tests__/guard-tests.test.ts +289 -0
- package/src/runtime/auth/__tests__/ipc-auth-context.test.ts +71 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +239 -0
- package/src/runtime/auth/__tests__/policy.test.ts +29 -0
- package/src/runtime/auth/__tests__/route-policy.test.ts +166 -0
- package/src/runtime/auth/__tests__/scopes.test.ts +109 -0
- package/src/runtime/auth/__tests__/subject.test.ts +149 -0
- package/src/runtime/auth/__tests__/token-service.test.ts +263 -0
- package/src/runtime/auth/context.ts +62 -0
- package/src/runtime/{actor-refresh-token-service.ts → auth/credential-service.ts} +112 -79
- package/src/runtime/auth/external-assistant-id.ts +69 -0
- package/src/runtime/auth/index.ts +37 -0
- package/src/runtime/auth/middleware.ts +127 -0
- package/src/runtime/auth/policy.ts +17 -0
- package/src/runtime/auth/route-policy.ts +261 -0
- package/src/runtime/auth/scopes.ts +64 -0
- package/src/runtime/auth/subject.ts +68 -0
- package/src/runtime/auth/token-service.ts +275 -0
- package/src/runtime/auth/types.ts +79 -0
- package/src/runtime/channel-approval-parser.ts +11 -5
- package/src/runtime/channel-approval-types.ts +1 -1
- package/src/runtime/channel-approvals.ts +22 -1
- package/src/runtime/guardian-action-followup-executor.ts +2 -2
- package/src/runtime/guardian-context-resolver.ts +15 -0
- package/src/runtime/guardian-decision-types.ts +23 -6
- package/src/runtime/guardian-outbound-actions.ts +4 -22
- package/src/runtime/guardian-reply-router.ts +5 -3
- package/src/runtime/http-server.ts +210 -182
- package/src/runtime/http-types.ts +11 -1
- package/src/runtime/local-actor-identity.ts +25 -0
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/approval-routes.ts +42 -59
- package/src/runtime/routes/channel-route-shared.ts +9 -41
- package/src/runtime/routes/channel-routes.ts +0 -2
- package/src/runtime/routes/conversation-routes.ts +39 -49
- package/src/runtime/routes/events-routes.ts +15 -22
- package/src/runtime/routes/guardian-action-routes.ts +46 -51
- package/src/runtime/routes/guardian-approval-interception.ts +6 -5
- package/src/runtime/routes/guardian-bootstrap-routes.ts +12 -8
- package/src/runtime/routes/guardian-refresh-routes.ts +2 -2
- package/src/runtime/routes/inbound-message-handler.ts +39 -45
- package/src/runtime/routes/pairing-routes.ts +9 -9
- package/src/runtime/routes/secret-routes.ts +90 -45
- package/src/runtime/routes/surface-action-routes.ts +12 -2
- package/src/runtime/routes/trust-rules-routes.ts +13 -0
- package/src/runtime/routes/twilio-routes.ts +3 -3
- package/src/runtime/session-approval-overrides.ts +86 -0
- package/src/security/keychain-to-encrypted-migration.ts +8 -1
- package/src/skills/frontmatter.ts +44 -1
- package/src/tools/permission-checker.ts +226 -74
- package/src/runtime/actor-token-service.ts +0 -234
- package/src/runtime/middleware/actor-token.ts +0 -265
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core auth types for the single-header JWT auth system.
|
|
3
|
+
*
|
|
4
|
+
* These types define the token claims, scope profiles, principal types,
|
|
5
|
+
* and the normalized AuthContext that downstream code consumes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Scope profiles — named bundles of permissions
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
export type ScopeProfile =
|
|
13
|
+
| 'actor_client_v1'
|
|
14
|
+
| 'gateway_ingress_v1'
|
|
15
|
+
| 'gateway_service_v1'
|
|
16
|
+
| 'ipc_v1';
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Individual scope strings
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
export type Scope =
|
|
23
|
+
| 'chat.read'
|
|
24
|
+
| 'chat.write'
|
|
25
|
+
| 'approval.read'
|
|
26
|
+
| 'approval.write'
|
|
27
|
+
| 'settings.read'
|
|
28
|
+
| 'settings.write'
|
|
29
|
+
| 'attachments.read'
|
|
30
|
+
| 'attachments.write'
|
|
31
|
+
| 'calls.read'
|
|
32
|
+
| 'calls.write'
|
|
33
|
+
| 'ingress.write'
|
|
34
|
+
| 'internal.write'
|
|
35
|
+
| 'feature_flags.read'
|
|
36
|
+
| 'feature_flags.write'
|
|
37
|
+
| 'ipc.all';
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Principal types — derived from the sub pattern
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
export type PrincipalType = 'actor' | 'svc_gateway' | 'ipc';
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Token audience — which service the JWT is intended for
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
export type TokenAudience = 'vellum-gateway' | 'vellum-daemon';
|
|
50
|
+
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// JWT claims — the payload inside the token
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
export interface TokenClaims {
|
|
56
|
+
iss: 'vellum-auth';
|
|
57
|
+
aud: TokenAudience;
|
|
58
|
+
sub: string;
|
|
59
|
+
scope_profile: ScopeProfile;
|
|
60
|
+
exp: number;
|
|
61
|
+
policy_epoch: number;
|
|
62
|
+
iat?: number;
|
|
63
|
+
jti?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// AuthContext — normalized auth state for downstream consumers
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
export interface AuthContext {
|
|
71
|
+
subject: string;
|
|
72
|
+
principalType: PrincipalType;
|
|
73
|
+
assistantId: string;
|
|
74
|
+
actorPrincipalId?: string;
|
|
75
|
+
sessionId?: string;
|
|
76
|
+
scopeProfile: ScopeProfile;
|
|
77
|
+
scopes: ReadonlySet<Scope>;
|
|
78
|
+
policyEpoch: number;
|
|
79
|
+
}
|
|
@@ -18,22 +18,28 @@ import type { ApprovalAction, ApprovalDecisionResult } from './channel-approval-
|
|
|
18
18
|
// ---------------------------------------------------------------------------
|
|
19
19
|
|
|
20
20
|
const APPROVE_ONCE_PHRASES = ['yes', 'approve', 'approve once', 'allow', 'go ahead'];
|
|
21
|
+
const APPROVE_10M_PHRASES = ['approve for 10 minutes', 'allow for 10 minutes', 'approve 10m', 'allow 10m', 'approve 10 min', 'allow 10 min'];
|
|
22
|
+
const APPROVE_THREAD_PHRASES = ['approve for thread', 'allow for thread', 'approve thread', 'allow thread'];
|
|
21
23
|
const APPROVE_ALWAYS_PHRASES = ['always', 'approve always', 'allow always'];
|
|
22
24
|
const REJECT_PHRASES = ['no', 'reject', 'deny', 'cancel'];
|
|
23
25
|
|
|
24
26
|
/**
|
|
25
|
-
* Build a Map from lowercased phrase to action.
|
|
26
|
-
*
|
|
27
|
-
*
|
|
27
|
+
* Build a Map from lowercased phrase to action. Longer phrases are
|
|
28
|
+
* inserted first so iteration order does not matter — we match on
|
|
29
|
+
* exact equality after normalising, not prefix matching.
|
|
28
30
|
*/
|
|
29
31
|
function buildPhraseMap(): Map<string, ApprovalAction> {
|
|
30
32
|
const map = new Map<string, ApprovalAction>();
|
|
31
33
|
|
|
32
|
-
// Insert longer phrases first so iteration order does not matter —
|
|
33
|
-
// we match on exact equality after normalising, not prefix matching.
|
|
34
34
|
for (const phrase of APPROVE_ALWAYS_PHRASES) {
|
|
35
35
|
map.set(phrase, 'approve_always');
|
|
36
36
|
}
|
|
37
|
+
for (const phrase of APPROVE_10M_PHRASES) {
|
|
38
|
+
map.set(phrase, 'approve_10m');
|
|
39
|
+
}
|
|
40
|
+
for (const phrase of APPROVE_THREAD_PHRASES) {
|
|
41
|
+
map.set(phrase, 'approve_thread');
|
|
42
|
+
}
|
|
37
43
|
for (const phrase of APPROVE_ONCE_PHRASES) {
|
|
38
44
|
map.set(phrase, 'approve_once');
|
|
39
45
|
}
|
|
@@ -14,7 +14,7 @@ import type { GuardianDecisionAction } from './guardian-decision-types.js';
|
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
|
|
16
16
|
/** The set of actions a user can take on an approval prompt. */
|
|
17
|
-
export type ApprovalAction = 'approve_once' | 'approve_always' | 'reject';
|
|
17
|
+
export type ApprovalAction = 'approve_once' | 'approve_10m' | 'approve_thread' | 'approve_always' | 'reject';
|
|
18
18
|
|
|
19
19
|
/** An action presented to the user as a tappable button or text option. */
|
|
20
20
|
export interface ApprovalActionOption {
|
|
@@ -10,9 +10,11 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { addRule } from '../permissions/trust-store.js';
|
|
13
|
+
import type { UserDecision } from '../permissions/types.js';
|
|
13
14
|
import { getTool } from '../tools/registry.js';
|
|
14
15
|
import { composeApprovalMessage } from './approval-message-composer.js';
|
|
15
16
|
import type {
|
|
17
|
+
ApprovalAction,
|
|
16
18
|
ApprovalDecisionResult,
|
|
17
19
|
ApprovalUIMetadata,
|
|
18
20
|
ChannelApprovalPrompt,
|
|
@@ -110,6 +112,25 @@ export function buildApprovalUIMetadata(
|
|
|
110
112
|
};
|
|
111
113
|
}
|
|
112
114
|
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// 2.5. Action → UserDecision mapping
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Map a channel-level `ApprovalAction` to the permission system's
|
|
121
|
+
* `UserDecision` type. Temporary approval modes (`approve_10m`,
|
|
122
|
+
* `approve_thread`) map directly to their `allow_*` counterparts so
|
|
123
|
+
* the permission pipeline can activate the appropriate override.
|
|
124
|
+
*/
|
|
125
|
+
function mapApprovalActionToUserDecision(action: ApprovalAction): UserDecision {
|
|
126
|
+
switch (action) {
|
|
127
|
+
case 'reject': return 'deny';
|
|
128
|
+
case 'approve_10m': return 'allow_10m';
|
|
129
|
+
case 'approve_thread': return 'allow_thread';
|
|
130
|
+
default: return 'allow';
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
113
134
|
// ---------------------------------------------------------------------------
|
|
114
135
|
// 3. Consume a user decision and apply it to the session
|
|
115
136
|
// ---------------------------------------------------------------------------
|
|
@@ -176,7 +197,7 @@ export function handleChannelDecision(
|
|
|
176
197
|
if (!resolved) return { applied: false };
|
|
177
198
|
|
|
178
199
|
// Map channel-level action to the permission system's UserDecision type.
|
|
179
|
-
const userDecision = decision.action
|
|
200
|
+
const userDecision = mapApprovalActionToUserDecision(decision.action);
|
|
180
201
|
if (decisionContext === undefined) {
|
|
181
202
|
resolved.session.handleConfirmationResponse(info.requestId, userDecision);
|
|
182
203
|
} else {
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
type GuardianActionRequest,
|
|
30
30
|
} from '../memory/guardian-action-store.js';
|
|
31
31
|
import { getLogger } from '../util/logger.js';
|
|
32
|
-
import {
|
|
32
|
+
import { mintDaemonDeliveryToken } from './auth/token-service.js';
|
|
33
33
|
import { deliverChannelReply } from './gateway-client.js';
|
|
34
34
|
import { composeGuardianActionMessageGenerative } from './guardian-action-message-composer.js';
|
|
35
35
|
import type { GuardianActionCopyGenerator } from './http-types.js';
|
|
@@ -115,7 +115,7 @@ async function executeMessageBack(
|
|
|
115
115
|
|
|
116
116
|
const gatewayBase = getGatewayInternalBaseUrl();
|
|
117
117
|
const deliverUrl = `${gatewayBase}/deliver/sms`;
|
|
118
|
-
const bearerToken =
|
|
118
|
+
const bearerToken = mintDaemonDeliveryToken();
|
|
119
119
|
|
|
120
120
|
await deliverChannelReply(
|
|
121
121
|
deliverUrl,
|
|
@@ -124,3 +124,18 @@ export function resolveRoutingState(ctx: Pick<GuardianRuntimeContext, 'trustClas
|
|
|
124
124
|
export function resolveRoutingStateFromRuntime(ctx: GuardianRuntimeContext): RoutingState {
|
|
125
125
|
return resolveRoutingState(ctx);
|
|
126
126
|
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Override the sourceChannel on a resolved GuardianRuntimeContext.
|
|
130
|
+
*
|
|
131
|
+
* The HTTP /messages endpoint resolves trust against a fixed internal
|
|
132
|
+
* channel ('vellum') but the request body carries the actual sourceChannel
|
|
133
|
+
* (e.g. the channel the gateway routed the request through). This helper
|
|
134
|
+
* copies the context with the caller-supplied sourceChannel.
|
|
135
|
+
*/
|
|
136
|
+
export function toGuardianRuntimeContext(
|
|
137
|
+
sourceChannel: import('../channels/types.js').ChannelId,
|
|
138
|
+
ctx: GuardianRuntimeContext,
|
|
139
|
+
): GuardianRuntimeContext {
|
|
140
|
+
return { ...ctx, sourceChannel };
|
|
141
|
+
}
|
|
@@ -44,6 +44,8 @@ export interface GuardianDecisionAction {
|
|
|
44
44
|
/** Canonical set of all guardian decision actions with their labels. */
|
|
45
45
|
export const GUARDIAN_DECISION_ACTIONS = {
|
|
46
46
|
approve_once: { action: 'approve_once', label: 'Approve once' },
|
|
47
|
+
approve_10m: { action: 'approve_10m', label: 'Allow 10 min' },
|
|
48
|
+
approve_thread: { action: 'approve_thread', label: 'Allow thread' },
|
|
47
49
|
approve_always: { action: 'approve_always', label: 'Approve always' },
|
|
48
50
|
reject: { action: 'reject', label: 'Reject' },
|
|
49
51
|
} as const satisfies Record<string, GuardianDecisionAction>;
|
|
@@ -54,16 +56,21 @@ export const GUARDIAN_DECISION_ACTIONS = {
|
|
|
54
56
|
*
|
|
55
57
|
* When `persistentDecisionsAllowed` is `false`, the `approve_always` action
|
|
56
58
|
* is excluded. When `forGuardianOnBehalf` is `true` (guardian acting on behalf
|
|
57
|
-
* of a requester), `approve_always`
|
|
58
|
-
*
|
|
59
|
+
* of a requester), both `approve_always` and the temporary modes are excluded
|
|
60
|
+
* since guardians cannot grant broad delegated allow modes on behalf of others.
|
|
61
|
+
*
|
|
62
|
+
* Temporary modes (`approve_10m`, `approve_thread`) are included for
|
|
63
|
+
* requester-side standard approval flows when persistent decisions are allowed.
|
|
59
64
|
*/
|
|
60
65
|
export function buildDecisionActions(opts?: {
|
|
61
66
|
persistentDecisionsAllowed?: boolean;
|
|
62
67
|
forGuardianOnBehalf?: boolean;
|
|
63
68
|
}): GuardianDecisionAction[] {
|
|
64
69
|
const showAlways = opts?.persistentDecisionsAllowed !== false && !opts?.forGuardianOnBehalf;
|
|
70
|
+
const showTemporary = opts?.persistentDecisionsAllowed !== false && !opts?.forGuardianOnBehalf;
|
|
65
71
|
return [
|
|
66
72
|
GUARDIAN_DECISION_ACTIONS.approve_once,
|
|
73
|
+
...(showTemporary ? [GUARDIAN_DECISION_ACTIONS.approve_10m, GUARDIAN_DECISION_ACTIONS.approve_thread] : []),
|
|
67
74
|
...(showAlways ? [GUARDIAN_DECISION_ACTIONS.approve_always] : []),
|
|
68
75
|
GUARDIAN_DECISION_ACTIONS.reject,
|
|
69
76
|
];
|
|
@@ -72,16 +79,26 @@ export function buildDecisionActions(opts?: {
|
|
|
72
79
|
/**
|
|
73
80
|
* Build the plain-text fallback instruction string that matches the given
|
|
74
81
|
* set of decision actions. Ensures the text always includes parser-compatible
|
|
75
|
-
* keywords
|
|
82
|
+
* keywords so text-based fallback remains actionable.
|
|
76
83
|
*/
|
|
77
84
|
export function buildPlainTextFallback(
|
|
78
85
|
promptText: string,
|
|
79
86
|
actions: GuardianDecisionAction[],
|
|
80
87
|
): string {
|
|
81
88
|
const hasAlways = actions.some(a => a.action === 'approve_always');
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
89
|
+
const has10m = actions.some(a => a.action === 'approve_10m');
|
|
90
|
+
const hasThread = actions.some(a => a.action === 'approve_thread');
|
|
91
|
+
|
|
92
|
+
if (hasAlways && has10m && hasThread) {
|
|
93
|
+
return `${promptText}\n\nReply "yes" to approve once, "approve for 10 minutes", "approve for thread", "always" to approve always, or "no" to reject.`;
|
|
94
|
+
}
|
|
95
|
+
if (hasAlways) {
|
|
96
|
+
return `${promptText}\n\nReply "yes" to approve once, "always" to approve always, or "no" to reject.`;
|
|
97
|
+
}
|
|
98
|
+
if (has10m && hasThread) {
|
|
99
|
+
return `${promptText}\n\nReply "yes" to approve once, "approve for 10 minutes", "approve for thread", or "no" to reject.`;
|
|
100
|
+
}
|
|
101
|
+
return `${promptText}\n\nReply "yes" to approve or "no" to reject.`;
|
|
85
102
|
}
|
|
86
103
|
|
|
87
104
|
// ---------------------------------------------------------------------------
|
|
@@ -16,8 +16,8 @@ import { sendMessage as sendSms } from "../messaging/providers/sms/client.js";
|
|
|
16
16
|
import { getCredentialMetadata } from "../tools/credentials/metadata-store.js";
|
|
17
17
|
import { getLogger } from "../util/logger.js";
|
|
18
18
|
import { normalizePhoneNumber } from "../util/phone.js";
|
|
19
|
-
import { readHttpToken } from "../util/platform.js";
|
|
20
19
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "./assistant-scope.js";
|
|
20
|
+
import { mintDaemonDeliveryToken } from "./auth/token-service.js";
|
|
21
21
|
import {
|
|
22
22
|
countRecentSendsToDestination,
|
|
23
23
|
createOutboundSession,
|
|
@@ -153,13 +153,7 @@ function deliverVerificationSms(
|
|
|
153
153
|
(async () => {
|
|
154
154
|
try {
|
|
155
155
|
const gatewayUrl = getGatewayInternalBaseUrl();
|
|
156
|
-
const bearerToken =
|
|
157
|
-
if (!bearerToken) {
|
|
158
|
-
log.error(
|
|
159
|
-
"Cannot deliver verification SMS: no runtime HTTP token available",
|
|
160
|
-
);
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
156
|
+
const bearerToken = mintDaemonDeliveryToken();
|
|
163
157
|
await sendSms(gatewayUrl, bearerToken, to, text, assistantId);
|
|
164
158
|
log.info({ to, assistantId }, "Verification SMS delivered");
|
|
165
159
|
} catch (err) {
|
|
@@ -184,13 +178,7 @@ function deliverVerificationTelegram(
|
|
|
184
178
|
(async () => {
|
|
185
179
|
try {
|
|
186
180
|
const gatewayUrl = getGatewayInternalBaseUrl();
|
|
187
|
-
const bearerToken =
|
|
188
|
-
if (!bearerToken) {
|
|
189
|
-
log.error(
|
|
190
|
-
"Cannot deliver verification Telegram message: no runtime HTTP token available",
|
|
191
|
-
);
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
181
|
+
const bearerToken = mintDaemonDeliveryToken();
|
|
194
182
|
const url = `${gatewayUrl}/deliver/telegram`;
|
|
195
183
|
const resp = await fetch(url, {
|
|
196
184
|
method: "POST",
|
|
@@ -646,13 +634,7 @@ function deliverVerificationSlack(
|
|
|
646
634
|
(async () => {
|
|
647
635
|
try {
|
|
648
636
|
const gatewayUrl = getGatewayInternalBaseUrl();
|
|
649
|
-
const bearerToken =
|
|
650
|
-
if (!bearerToken) {
|
|
651
|
-
log.error(
|
|
652
|
-
"Cannot deliver verification Slack DM: no runtime HTTP token available",
|
|
653
|
-
);
|
|
654
|
-
return;
|
|
655
|
-
}
|
|
637
|
+
const bearerToken = mintDaemonDeliveryToken();
|
|
656
638
|
const url = `${gatewayUrl}/deliver/slack`;
|
|
657
639
|
const resp = await fetch(url, {
|
|
658
640
|
method: "POST",
|
|
@@ -108,6 +108,8 @@ export interface GuardianReplyResult {
|
|
|
108
108
|
|
|
109
109
|
const VALID_ACTIONS: ReadonlySet<string> = new Set([
|
|
110
110
|
'approve_once',
|
|
111
|
+
'approve_10m',
|
|
112
|
+
'approve_thread',
|
|
111
113
|
'approve_always',
|
|
112
114
|
'reject',
|
|
113
115
|
]);
|
|
@@ -476,9 +478,9 @@ export async function routeGuardianReply(
|
|
|
476
478
|
// Decision-bearing disposition from the engine
|
|
477
479
|
let decisionAction = engineResult.disposition as ApprovalAction;
|
|
478
480
|
|
|
479
|
-
// Guardians cannot
|
|
480
|
-
// this too, but enforce it here for clarity.
|
|
481
|
-
if (decisionAction === 'approve_always') {
|
|
481
|
+
// Guardians cannot use broad allow modes — the canonical primitive
|
|
482
|
+
// enforces this too, but enforce it here for clarity.
|
|
483
|
+
if (decisionAction === 'approve_always' || decisionAction === 'approve_10m' || decisionAction === 'approve_thread') {
|
|
482
484
|
decisionAction = 'approve_once';
|
|
483
485
|
}
|
|
484
486
|
|