@msg91comm/m91 1.1.0 → 1.2.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/CHANGELOG.md +35 -0
- package/README.md +241 -19
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/integrations/claude-agent-sdk.d.ts +63 -0
- package/dist/src/integrations/claude-agent-sdk.d.ts.map +1 -0
- package/dist/src/integrations/claude-agent-sdk.js +109 -0
- package/dist/src/integrations/claude-agent-sdk.js.map +1 -0
- package/dist/src/integrations/google-adk.d.ts +47 -0
- package/dist/src/integrations/google-adk.d.ts.map +1 -0
- package/dist/src/integrations/google-adk.js +84 -0
- package/dist/src/integrations/google-adk.js.map +1 -0
- package/dist/src/integrations/index.d.ts +7 -3
- package/dist/src/integrations/index.d.ts.map +1 -1
- package/dist/src/integrations/index.js +6 -2
- package/dist/src/integrations/index.js.map +1 -1
- package/dist/src/integrations/langchain.d.ts +56 -5
- package/dist/src/integrations/langchain.d.ts.map +1 -1
- package/dist/src/integrations/langchain.js +56 -2
- package/dist/src/integrations/langchain.js.map +1 -1
- package/dist/src/integrations/mastra.d.ts +75 -0
- package/dist/src/integrations/mastra.d.ts.map +1 -0
- package/dist/src/integrations/mastra.js +109 -0
- package/dist/src/integrations/mastra.js.map +1 -0
- package/dist/src/integrations/openai-agents.d.ts +61 -0
- package/dist/src/integrations/openai-agents.d.ts.map +1 -0
- package/dist/src/integrations/openai-agents.js +127 -0
- package/dist/src/integrations/openai-agents.js.map +1 -0
- package/dist/src/integrations/specs.d.ts +42 -0
- package/dist/src/integrations/specs.d.ts.map +1 -1
- package/dist/src/integrations/specs.js +61 -0
- package/dist/src/integrations/specs.js.map +1 -1
- package/dist/src/integrations/vercel-ai.d.ts +44 -6
- package/dist/src/integrations/vercel-ai.d.ts.map +1 -1
- package/dist/src/integrations/vercel-ai.js +38 -3
- package/dist/src/integrations/vercel-ai.js.map +1 -1
- package/dist/src/integrations/zod-shapes.d.ts +19 -0
- package/dist/src/integrations/zod-shapes.d.ts.map +1 -0
- package/dist/src/integrations/zod-shapes.js +44 -0
- package/dist/src/integrations/zod-shapes.js.map +1 -0
- package/dist/src/platform.d.ts +1 -1
- package/dist/src/platform.d.ts.map +1 -1
- package/dist/src/platform.js +1 -1
- package/dist/src/platform.js.map +1 -1
- package/dist/src/url-builder.js +1 -1
- package/dist/src/url-builder.js.map +1 -1
- package/examples/basic-alert.ts +1 -1
- package/examples/claude-agent-sdk.ts +23 -0
- package/examples/deep-agents.ts +31 -0
- package/examples/google-adk.ts +39 -0
- package/examples/mastra.ts +41 -0
- package/examples/openai-agents.ts +33 -0
- package/examples/webhook-urls.ts +1 -1
- package/package.json +63 -11
- package/src/index.ts +1 -1
- package/src/integrations/claude-agent-sdk.ts +158 -0
- package/src/integrations/google-adk.ts +122 -0
- package/src/integrations/index.ts +7 -3
- package/src/integrations/langchain.ts +109 -6
- package/src/integrations/mastra.ts +178 -0
- package/src/integrations/openai-agents.ts +173 -0
- package/src/integrations/specs.ts +104 -0
- package/src/integrations/vercel-ai.ts +59 -7
- package/src/integrations/zod-shapes.ts +55 -0
- package/src/platform.ts +1 -1
- package/src/url-builder.ts +1 -1
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Vercel AI SDK tools.
|
|
2
|
+
* Vercel AI SDK: two tools, and a gate for your own tools.
|
|
3
|
+
*
|
|
4
|
+
* **Tools** the model calls when it decides to ask (`createM91Tools`).
|
|
5
|
+
*
|
|
6
|
+
* **Gate** (`createM91ToolApproval`) plugs into AI SDK 6+'s `toolApproval`
|
|
7
|
+
* option: every call to the tools you name rings a phone first, and runs only
|
|
8
|
+
* if a person approves. The model cannot skip it, because it never decides to
|
|
9
|
+
* ask: the SDK asks for it.
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* const { text } = await generateText({
|
|
13
|
+
* model: 'openai/gpt-5-mini',
|
|
14
|
+
* tools: { issueRefund, deleteUser },
|
|
15
|
+
* toolApproval: createM91ToolApproval(client, { tools: ['issueRefund', 'deleteUser'] }),
|
|
16
|
+
* stopWhen: isStepCount(5),
|
|
17
|
+
* prompt: 'Refund order ORD-40122.',
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
3
20
|
*
|
|
4
21
|
* ```ts
|
|
5
22
|
* import { M91Client } from '@msg91comm/m91';
|
|
@@ -13,7 +30,7 @@
|
|
|
13
30
|
* m91_request_approval: await createM91ApprovalTool(client),
|
|
14
31
|
* m91_send_alert: await createM91AlertTool(client),
|
|
15
32
|
* },
|
|
16
|
-
*
|
|
33
|
+
* stopWhen: isStepCount(10),
|
|
17
34
|
* prompt: 'Look into order ORD-40122 and refund it if it checks out.',
|
|
18
35
|
* });
|
|
19
36
|
* ```
|
|
@@ -23,6 +40,8 @@
|
|
|
23
40
|
* dependencies.
|
|
24
41
|
*/
|
|
25
42
|
|
|
43
|
+
import type { Tool, ToolApprovalStatus, ToolSet } from 'ai';
|
|
44
|
+
|
|
26
45
|
import type { M91Client } from '../client.js';
|
|
27
46
|
import {
|
|
28
47
|
ALERT_DESCRIPTION,
|
|
@@ -33,6 +52,9 @@ import {
|
|
|
33
52
|
type AlertDefaults,
|
|
34
53
|
type ApprovalArgs,
|
|
35
54
|
type ApprovalDefaults,
|
|
55
|
+
type GateOptions,
|
|
56
|
+
decideToolCall,
|
|
57
|
+
needsHuman,
|
|
36
58
|
runAlert,
|
|
37
59
|
runApproval,
|
|
38
60
|
} from './specs.js';
|
|
@@ -63,7 +85,7 @@ async function aiModule(): Promise<AiModule> {
|
|
|
63
85
|
export async function createM91ApprovalTool(
|
|
64
86
|
client: M91Client,
|
|
65
87
|
defaults: ApprovalDefaults = {},
|
|
66
|
-
): Promise<
|
|
88
|
+
): Promise<Tool<ApprovalArgs, string>> {
|
|
67
89
|
const { tool, jsonSchema } = await aiModule();
|
|
68
90
|
return tool({
|
|
69
91
|
description: APPROVAL_DESCRIPTION,
|
|
@@ -71,29 +93,59 @@ export async function createM91ApprovalTool(
|
|
|
71
93
|
// and the argument docs stay in one file shared with every other framework.
|
|
72
94
|
inputSchema: jsonSchema(APPROVAL_SCHEMA),
|
|
73
95
|
execute: (args: ApprovalArgs) => runApproval(client, args, defaults),
|
|
74
|
-
})
|
|
96
|
+
}) as Tool<ApprovalArgs, string>;
|
|
75
97
|
}
|
|
76
98
|
|
|
77
99
|
/** The fire-and-forget alert. Returns `"sent:delivered=N"` or `"error: …"`. */
|
|
78
100
|
export async function createM91AlertTool(
|
|
79
101
|
client: M91Client,
|
|
80
102
|
defaults: AlertDefaults = {},
|
|
81
|
-
): Promise<
|
|
103
|
+
): Promise<Tool<AlertArgs, string>> {
|
|
82
104
|
const { tool, jsonSchema } = await aiModule();
|
|
83
105
|
return tool({
|
|
84
106
|
description: ALERT_DESCRIPTION,
|
|
85
107
|
inputSchema: jsonSchema(ALERT_SCHEMA),
|
|
86
108
|
execute: (args: AlertArgs) => runAlert(client, args, defaults),
|
|
87
|
-
})
|
|
109
|
+
}) as Tool<AlertArgs, string>;
|
|
88
110
|
}
|
|
89
111
|
|
|
90
112
|
/** Both, keyed by tool name, ready to spread into `tools: {…}`. */
|
|
91
113
|
export async function createM91Tools(
|
|
92
114
|
client: M91Client,
|
|
93
115
|
defaults: ApprovalDefaults & AlertDefaults = {},
|
|
94
|
-
): Promise<
|
|
116
|
+
): Promise<ToolSet> {
|
|
95
117
|
return {
|
|
96
118
|
m91_request_approval: await createM91ApprovalTool(client, defaults),
|
|
97
119
|
m91_send_alert: await createM91AlertTool(client, defaults),
|
|
98
120
|
};
|
|
99
121
|
}
|
|
122
|
+
|
|
123
|
+
/** The fields of an AI SDK tool call the gate reads. */
|
|
124
|
+
interface ApprovalRequestLike {
|
|
125
|
+
toolCall: { toolName: string; input: unknown; toolCallId: string };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* A `toolApproval` function for `generateText` / `streamText` / `ToolLoopAgent`.
|
|
130
|
+
*
|
|
131
|
+
* Calls to the tools in `options.tools` block while M91 rings a phone, then run
|
|
132
|
+
* if a person approves and come back to the model as denied otherwise. Every
|
|
133
|
+
* other call is `not-applicable` and runs as normal. Not synchronous: it waits
|
|
134
|
+
* up to `timeoutSeconds` (default 300) for an answer.
|
|
135
|
+
*/
|
|
136
|
+
export function createM91ToolApproval(
|
|
137
|
+
client: M91Client,
|
|
138
|
+
options: GateOptions & { tools: NonNullable<GateOptions['tools']> },
|
|
139
|
+
): (request: ApprovalRequestLike) => Promise<ToolApprovalStatus> {
|
|
140
|
+
return async ({ toolCall }) => {
|
|
141
|
+
if (!(await needsHuman(options, toolCall.toolName, toolCall.input))) return 'not-applicable';
|
|
142
|
+
const decision = await decideToolCall(
|
|
143
|
+
client,
|
|
144
|
+
{ toolName: toolCall.toolName, input: toolCall.input, callId: toolCall.toolCallId },
|
|
145
|
+
options,
|
|
146
|
+
);
|
|
147
|
+
return decision.approved
|
|
148
|
+
? { type: 'approved', reason: decision.reason }
|
|
149
|
+
: { type: 'denied', reason: decision.reason };
|
|
150
|
+
};
|
|
151
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The approval and alert arguments as zod shapes, for frameworks that only
|
|
3
|
+
* take zod (Claude Agent SDK, Mastra, Google ADK).
|
|
4
|
+
*
|
|
5
|
+
* Built from the zod the caller already has, passed in, so this package never
|
|
6
|
+
* imports zod itself and the descriptions stay the ones in `specs.ts`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ALERT_SCHEMA, APPROVAL_SCHEMA } from './specs.js';
|
|
10
|
+
|
|
11
|
+
/** The slice of zod this file uses; v3 and v4 both satisfy it. */
|
|
12
|
+
export interface ZodLike {
|
|
13
|
+
string(): any;
|
|
14
|
+
number(): any;
|
|
15
|
+
enum(values: readonly [string, ...string[]]): any;
|
|
16
|
+
object(shape: Record<string, any>): any;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const SEVERITIES = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'] as const;
|
|
20
|
+
|
|
21
|
+
export function approvalShape(z: ZodLike): Record<string, any> {
|
|
22
|
+
const p = APPROVAL_SCHEMA.properties;
|
|
23
|
+
return {
|
|
24
|
+
title: z.string().describe(p.title.description),
|
|
25
|
+
customId: z.string().describe(p.customId.description),
|
|
26
|
+
description: z.string().optional().describe(p.description.description),
|
|
27
|
+
severity: z.enum(SEVERITIES).optional().describe(p.severity.description),
|
|
28
|
+
approveLabel: z.string().optional().describe(p.approveLabel.description),
|
|
29
|
+
rejectLabel: z.string().optional().describe(p.rejectLabel.description),
|
|
30
|
+
timeoutSeconds: z.number().optional().describe(p.timeoutSeconds.description),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function alertShape(z: ZodLike): Record<string, any> {
|
|
35
|
+
const p = ALERT_SCHEMA.properties;
|
|
36
|
+
return {
|
|
37
|
+
title: z.string().describe(p.title.description),
|
|
38
|
+
customId: z.string().optional().describe(p.customId.description),
|
|
39
|
+
description: z.string().optional().describe(p.description.description),
|
|
40
|
+
severity: z.enum(SEVERITIES).optional().describe(p.severity.description),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** zod is an optional peer dependency: import it only when asked, and say so if it is missing. */
|
|
45
|
+
export async function loadZod(framework: string): Promise<ZodLike> {
|
|
46
|
+
try {
|
|
47
|
+
const specifier = 'zod';
|
|
48
|
+
const mod = (await import(specifier)) as { z?: ZodLike } & ZodLike;
|
|
49
|
+
return mod.z ?? mod;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
throw new Error(`The ${framework} integration needs zod. Install it with: npm install zod`, {
|
|
52
|
+
cause: error,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
package/src/platform.ts
CHANGED
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
} from './models.js';
|
|
42
42
|
import { type SendOptions, checkDelivery } from './client.js';
|
|
43
43
|
|
|
44
|
-
export const DEFAULT_BASE_URL = 'https://m91.msg91.com';
|
|
44
|
+
export const DEFAULT_BASE_URL = 'https://m91-api.msg91.com';
|
|
45
45
|
export const API_KEY_PREFIX = 'm91sk_';
|
|
46
46
|
|
|
47
47
|
export interface PlatformOptions extends TransportOptions {
|
package/src/url-builder.ts
CHANGED
|
@@ -63,7 +63,7 @@ export function normalizeSendLink(sendLink: string): string {
|
|
|
63
63
|
// link rather than a mistyped one.
|
|
64
64
|
if (segments.length < 2 || segments[segments.length - 2] !== 's') {
|
|
65
65
|
throw new M91ValidationError(
|
|
66
|
-
`sendLink must look like https://m91.msg91.com/s/<token> — ` +
|
|
66
|
+
`sendLink must look like https://m91-api.msg91.com/s/<token> — ` +
|
|
67
67
|
`no /s/<token> found in '${parsed.pathname}'`,
|
|
68
68
|
);
|
|
69
69
|
}
|